草庐IT

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

coder 2023-12-09 原文

到目前为止我做了什么:

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

我的问题 是,当我使用 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/

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

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  7. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  8. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

随机推荐