android - 为什么带 handle 的连续自动对焦相机不允许切换相机闪光灯?

标签 android android-camera

到目前为止我做了什么:

我已经实现了用于读取二维码的自定义摄像头,需要继续聚焦摄像头以更好地读取二维码。

我的问题 是,当我使用 handle 每隔一秒对焦一次时,相机闪光灯开\关按钮不起作用,或者打开和关闭相机闪光灯需要很长时间。当我删除每秒自动对焦相机的代码(可运行和处理程序)时,一切正常。

我想要的是每当相机移动时自动快速对焦,并且能够在不使用 Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE 的情况下按需快速打开和关闭闪光灯。因为它不适用于 API<14 .

我用过Camera.Parameters.FOCUS_MODE_AUTO但它只在开始时对相机进行一次对焦,这就是为什么我每秒都使用处理程序对相机进行对焦。

Min SDK项目版本为9.

我的相机 Activity 是

public class CameraActivityNew extends Activity implements OnClickListener,
        Camera.PreviewCallback {

    CameraPreviewNew mPreview;
    FrameLayout flCameraPreview;
    ImageButton ibFlashButton;
    Boolean isFlashOn = false;

    Camera mCamera;

    private Handler mAutoFocusHandler;
    private boolean mPreviewing = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        mAutoFocusHandler = new Handler();
        setContentView(R.layout.activity_camera);
        findSetupViews();
        mPreview = new CameraPreviewNew(getApplicationContext(), this,
                autoFocusCB);
        flCameraPreview.addView(mPreview);
    }

    private Runnable doAutoFocus = new Runnable() {
        public void run() {
            if (mCamera != null && mPreviewing) {
                mCamera.autoFocus(autoFocusCB);
            }
        }
    };
    Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
        public void onAutoFocus(boolean success, Camera camera) {
            mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
        }
    };

    @Override
    protected void onResume() {

        super.onResume();
        try {
            mCamera = Camera.open();
            if (mCamera == null) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        mPreview.setCamera(mCamera);
        mPreview.showSurfaceView();
        mPreviewing = true;

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mCamera != null) {
            mPreview.setCamera(null);
            mCamera.cancelAutoFocus();
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mPreview.hideSurfaceView();
            mPreviewing = false;
            mCamera = null;
        }
    }

    private void findSetupViews() {

        flCameraPreview = (FrameLayout) findViewById(R.id.flCameraPreview);
        ibFlashButton = (ImageButton) findViewById(R.id.ibFlash);
        ibFlashButton.setOnClickListener(this);

        if (getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA_FLASH)) {
            ibFlashButton.setVisibility(View.VISIBLE);
            ibFlashButton.setOnClickListener(this);
        } else {
            ibFlashButton.setVisibility(View.GONE);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.ibFlash:
            if (isFlashOn) {
                mPreview.setCameraFlashLight(false);
                isFlashOn = false;
                ibFlashButton.setImageResource(R.drawable.flashoff);
            } else {
                mPreview.setCameraFlashLight(true);
                ibFlashButton.setImageResource(R.drawable.flashon);
                isFlashOn = true;
            }
            break;
        }
    }

    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {
        // processed here qr code and works fine if camera focus
        //now removed to narrow the code for posting the question
    }

}

Camera Preview 类是:

public class CameraPreviewNew extends ViewGroup implements Callback {

    public static final int CAMERA_BACK = 0;
    public static final int CAMERA_FRONT = 1;
    public Camera mCamera = null;
    private Context context = null;

    SurfaceView mSurfaceView;
    SurfaceHolder mSurfaceHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    PreviewCallback mPreviewCallback;
    AutoFocusCallback mAutoFocusCallback;

    public CameraPreviewNew(Context context,

    PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
        super(context);
        mPreviewCallback = previewCallback;
        mAutoFocusCallback = autoFocusCb;
        this.context = context;
        mSurfaceView = new SurfaceView(context);
        addView(mSurfaceView);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters()
                    .getSupportedPreviewSizes();
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        final int width = resolveSize(getSuggestedMinimumWidth(),
                widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(),
                heightMeasureSpec);
        setMeasuredDimension(width, height);

    }

    public void hideSurfaceView() {
        mSurfaceView.setVisibility(View.INVISIBLE);
    }

    public void showSurfaceView() {
        mSurfaceView.setVisibility(View.VISIBLE);
    }

    public void surfaceCreated(SurfaceHolder holder) {

        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Log.e("logtag", "IOException caused by setPreviewDisplay()",
                    exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {

        if (mCamera != null) {
            mCamera.cancelAutoFocus();
            mCamera.stopPreview();
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if (holder.getSurface() == null) {

            return;
        }

        if (mCamera != null) {

            Camera.Parameters parameters = mCamera.getParameters();
            mPreviewSize = getBestPreviewSize(mCamera.getParameters(), w, h);
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            requestLayout();

            mCamera.setParameters(parameters);
            mCamera.setPreviewCallback(mPreviewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(mAutoFocusCallback);
            setCameraDisplayOrientation(0);
        }
    }

    private void setCameraDisplayOrientation(int cameraId) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = ((WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror
        } else { // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        mCamera.setDisplayOrientation(result);
    }

    protected static Comparator<Size> newSizeComparator() {
        return new Comparator<Size>() {

            @Override
            public int compare(Size lhs, Size rhs) {
                return Integer.valueOf(rhs.height * rhs.width).compareTo(
                        lhs.height * lhs.width);
            }
        };
    }

    private Size getBestPreviewSize(Parameters parameters, int screenWidth,
            int screenHeight) {
        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();

        Collections.sort(supportedSizes, newSizeComparator());

        int previewHeight = screenHeight;
        int previewWidth = screenWidth;

        if (previewHeight > previewWidth) {
            int swap = previewWidth;
            previewWidth = previewHeight;
            previewHeight = swap;
        }

        Size bestSize = null;
        float bestRatio = 999;
        for (Size s : supportedSizes) {

            if (s.height > s.width) {
                int swap = s.width;
                s.width = s.height;
                s.height = swap;
            }

            float cameraRatio = ((float) s.height / (float) s.width);
            float screenRatio = ((float) previewHeight)
                    / ((float) previewWidth);

            if ((s.height >= previewHeight) && (s.width >= previewWidth)) {
                float ratioDiff = cameraRatio - screenRatio;
                if ((ratioDiff < 0.19) && (ratioDiff > -0.19)
                        && (Math.abs(bestRatio) > Math.abs(ratioDiff))) {
                    bestSize = s;
                    bestRatio = ratioDiff;
                }
            }
        }
        return bestSize;
    }

    public void setCameraFlashLight(Boolean setFlash) {

        Parameters _parameters = mCamera.getParameters();

        if (setFlash) {
            _parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
        } else {
            _parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
        }
        mCamera.setParameters(_parameters);
        mCamera.startPreview();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                previewWidth = mPreviewSize.width;
                previewHeight = mPreviewSize.height;
            }

            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height
                        / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                        (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width
                        / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2, width,
                        (height + scaledChildHeight) / 2);
            }
        }

    }

}

最佳答案

我发现您的自动对焦处理代码存在一些问题。
分析结果

你的自动对焦有周期。

解释

a) Camera Preview Class mAutoFocusCallback is set with the autoFocusCb of the Camera Activity.

    public CameraPreviewNew(Context context,...,AutoFocusCallback autoFocusCb) 
    {
        super(context);
        mAutoFocusCallback = autoFocusCb;
        ...
    }

b)surfaceChanged is called once, at the time of loading the activity. The camera is requested to Auto Focus.

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 
    {
        if (mCamera != null) 
        {
            ...
            mCamera.startPreview();
            /*Auto focus camera and call <code>mAutoFocusCallback</code> after autofocus.*/
            mCamera.autoFocus(mAutoFocusCallback); 
            ...
       }
    }

c) On completion of the autofocus the mAutoFocusCallback callback is called. mAutoFocusCallback->autoFocusCb->onAutoFocus()
Camera Activity

    Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback()         {
        public void onAutoFocus(boolean success, Camera camera) {
            mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
        }
};

d)onAutoFocus schedules one more autoFocus after 1000 millisecons, 1 sec.
Camera Activity

    public void onAutoFocus(boolean success, Camera camera) {
        mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
    }  

e)After one second the messages is passed to handler that calles the runnable doAutoFocus requesting camera to auto focus, similar to b) above.

    private Runnable doAutoFocus = new Runnable() {
        public void run() {
            if (mCamera != null && mPreviewing) {
                mCamera.autoFocus(autoFocusCB);
            }
        }
    };

f) After completion of the autoFocus, the autoFocusCB is called again, similar to c) above. and cycle continues.

    Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
        public void onAutoFocus(boolean success, Camera camera) {
            mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
        }
    };

解决方案

我很困惑为什么要这样实现。周期可能是不听闪光灯启用/禁用调用的原因。您需要删除下面的代码并做一些有意义的事情,否则将 onAutoFocus() 留空。

Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
    public void onAutoFocus(boolean success, Camera camera) {
    /*REMOVE LINE BELOW*/
        mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
    }
};

要在每次相机移动时自动对焦,您需要借助手机随附的运动传感器。你可以谷歌一下

希望对您有所帮助。
快乐编码...

关于android - 为什么带 handle 的连续自动对焦相机不允许切换相机闪光灯?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31741871/

相关文章:

BOOT_COMPLETED 上的 Android BroadcastReceiver 不启动警报

java - 安卓振动器

android - 将 ARToolkit 标记跟踪添加到 Tango

android - 使用脸部滤镜录制视频

Android Camera.takePicture - 可以禁用快门声音和预览表面吗?

android - Play 商店在应用内购买产品最高限额

android - Phonegap HTML5/Android App - Iframe 高度问题

android - 相机 Intent 不添加额外的

android - 在相机 Activity 期间按后退按钮停止应用程序

android - 在 Android 中使用 PhoneGap 选择图像/视频