拍照前打闪的注意事项

前言

在实现拍照前打闪的时候,主要遇到了两点问题,第一就是平台不同,对于AE状态的判断有很大的区别,这也导致了实现拍照前打闪需要多考虑一下不同平台的兼容问题;第二就是拍照前打闪的实现效果跟自己手机上的拍照前打闪效果有很大的区别,我原本一开始实现出来的效果是:预打闪之后,拍照,然后再一次打闪,拍出来的照片也因此变得很暗,这个效果也不是我们想要的。

官方AE模式设置

private void changeAEMode(CaptureRequest.Builder captruebuilder) {
        switch (currentFlashState) {
            case FLASH_AUTO:
                //高通平台
                captruebuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                captruebuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
                //mtk平台
                /*mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);*/
                break;
            case FLASH_ON:
                captruebuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
                captruebuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
                break;
            case FLASH_OFF:
                //关闭闪光灯
                captruebuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                captruebuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
                break;
            case FLASH_TORCH:
                //闪光灯一直打开,一般用作补光的时候使用
                captruebuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                captruebuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
                break;
        }
    }

问题解决

AE状态兼容问题

在高通平台下,预览时候的AE状态都是预想中的状态,当闪光灯模式是关闭的情况下,AEState在收敛完成之后之后出现CONTROL_AE_STATE_CONVERGED,不会出现其他情况。在闪光灯模式开启的情况下,收敛完成会出现CONTROL_AE_STATE_FLASH_REQUIRED状态。而自动模式下则会自动收敛并返回相应对的AE状态。

而在MTK平台的情况下,无论什么闪光灯模式,出现的AE状态都是自动模式返回的AE状态,故此一般的拍照前打闪的判断就不能运用在MTK平台的机器上面,需要对其进行一个判断。

预打闪照片效果问题

按照现有的网上常见的打闪流程,其实是做不到我们原生相机的打闪效果。

大部分的教程都是先对AF进行锁定,再判断AF状态已经锁定之后再进行AE的预闪trigger,再预闪完之后再将AE进行锁定,最后再进行拍照。用这么一个流程的话,其实也能做出来,但是可以看到预打闪的时间很短,而且第二次打闪之前照片就被拍下来了。

其实我们平时注意我们手机的原生相机的打闪过程的话,其实也会发现拍照前打闪不应该是这个流程,按照上面那个流程的话,一切都是串行的,简单来说就是再对焦完成之后才开始对AE进行预闪然后再锁AE。但是原生相机的流程是对焦跟AE的预打闪其实是同时进行的,不应该有一个前后顺序。

大致的顺序应该是下面这样的,这个是参考了另外一篇文章的流程。相关连接:Camera2 APP Flash 打闪流程及原理分析 | 码农家园 (codenong.com)

1预拍照结束的判定条件为AE状态返回PEPCAPTURE状态,当该状态返回即AETRIGGER结束,预闪结束。该流程结束后才可进行下一次的Capture请求动作。
2 下一步的Capture请求动作可以做AF的TRIGGER,即AF的收敛过程,当AF状态达到完成的几种状态后即可,进行主拍照流程。该流程不做Flash_Mode 参数的下发。

第一步跟第二步可以同时在一个请求中完成,这样效果更好,在请求结束后判断ae跟af的状态即可。
3 主拍照过程需要再次下发FLASH_MODE,该参数下发后再Capture请求过程会进行主闪的打闪过程。
4 拍照结束后需要释放AE AF的状态,从而保证下次拍照AF AE状态正常。
释放过程还是通过Capture请求过程完成,主要设定AE/AF TRIGGER的状态为CANCEL状态,即可取消上一次的TRIGGER过程。
取消TRIGGER过程后就可以进行预览参数的回复,即做一次预览的请求。
5 预览请求过程只要保持之前的预览参数,AE/AFTRIGGER的状态置为IDLE就可完成整个Flash拍照流程。

我把我的代码实现放出来,可能可以直观一点。

if (isFinishSavePhoto) {
            isFinishSavePhoto = false;
            if (canReprocess) {
                //可以reprocess
                /*ZSLPair bestFrame = zslCoordinator.getBestFrame();
                if (bestFrame!=null){
                    recaptureRequest(bestFrame);
                    zslCoordinator.getImageBuffer().remove(bestFrame.getImage());
                    zslCoordinator.getResultBuffer().remove(bestFrame.getResult());
                }
                else {
                    try {
                        throw new Exception("No Best frame found");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }*/
                recaptureRequest(null);
            } else {
                //只需要关注这个函数就行,这个是不支持ZSL情况下的拍照方法。
                lockFocus();
            }

        }


    }

//拍照前锁定AF
    private void lockFocus() {
        //这个是先锁AF
        /*mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
        mState = STATE_WAITING_LOCK;
        try {
            System.out.println("lockfocus:"+mPreviewRequestBuilder.build());
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }*/
        //我们这波考虑先看看AE
        Toast.makeText(getContext(), "isHardWareVendorMediaTek():" + isHardWareVendorMediaTek(), Toast.LENGTH_SHORT).show();
        System.out.println(isHardWareVendorQualcomm() ? "是高通" : "不是高通");
        System.out.println(isHardWareVendorMediaTek() ? "是MTK" : "不是MTK");
        if (isHardWareVendorQualcomm()) {
            //如果是高通平台,原始代码就是兼容的
            mState = STATE_WAITING_LOCK;
            System.out.println("希望锁定AE");
            try {
                mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
        if (isHardWareVendorMediaTek()) {
            //MTK的话,就要做操作了
            mState = STATE_WAITING_LOCK;
            try {
                mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }


    }

   CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {

        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
            prepare(result);
        }


        private void prepare(TotalCaptureResult result) {
            switch (mState) {
                case STATE_PREVIEW:
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    //System.out.println(resultstate);
                    previewAEState = aeState;
                    break;
                case STATE_WAITING_LOCK:
                    //查看AF的状态
                    /*Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    System.out.println("afState:"+afState);
                    if (currentFlashState==0||currentFlashState==3){
                        mState = STATE_PICTURE_TAKEN;
                        captureStillPicture();
                    }
                    else {
                        if (afState == null) {
                            //不支持AF,就直接拍
                            mState = STATE_PICTURE_TAKEN;
                            captureStillPicture();
                        }

                        else if (afState == CONTROL_AF_STATE_NOT_FOCUSED_LOCKED || afState == CONTROL_AF_STATE_FOCUSED_LOCKED) {
                            Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                            System.out.println("aeState:"+aeState);
                            if (aeState == null || aeState == CONTROL_AE_STATE_CONVERGED) {
                                //收敛完成,不需要补光之类的东西
                                mState = STATE_PICTURE_TAKEN;
                                captureStillPicture();
                            } else {
                                //不过其他状态,直接预打闪
                                runPrecaptureSequence();
                            }
                        }
                    }*/
                    //这波先看AE
                    if (isHardWareVendorQualcomm()){
                        aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                        if (currentFlashState == 0 || currentFlashState == 3) {
                            mState = STATE_PICTURE_TAKEN;
                            captureStillPicture();
                        } else {
                            //打开闪光灯和自动闪光灯模式
                            if (aeState == null || aeState == CONTROL_AE_STATE_CONVERGED) {
                                //不支持AE
                                mState = STATE_PICTURE_TAKEN;
                                captureStillPicture();
                            } else if (aeState == CONTROL_AE_STATE_FLASH_REQUIRED || aeState == CONTROL_AE_STATE_PRECAPTURE) {
                                //需要补光,即都需要预打闪
                                runPrecaptureSequence();
                            }

                        }
                    }
                    if (isHardWareVendorMediaTek()){
                        aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                        if (currentFlashState == 0 || currentFlashState == 3) {
                            mState = STATE_PICTURE_TAKEN;
                            captureStillPicture();
                        }
                        else if (currentFlashState==1){
                            //闪光灯打开状态,无论怎样都预打闪
                            runPrecaptureSequence();
                        }
                        else if (currentFlashState==2){
                            if (aeState == null || aeState == CONTROL_AE_STATE_CONVERGED) {
                                //不支持AE
                                mState = STATE_PICTURE_TAKEN;
                                captureStillPicture();
                            } else if (aeState == CONTROL_AE_STATE_FLASH_REQUIRED || aeState == CONTROL_AE_STATE_PRECAPTURE) {
                                //需要补光,即都需要预打闪
                                runPrecaptureSequence();
                            }
                        }
                    }

                    break;
                case STATE_WAITING_PRECAPTURE:
                    /*Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    System.out.println("STATE_WAITING_PRECAPTURE之后的状态:"+aeState);
                    if (aeState==null||aeState==CONTROL_AE_STATE_FLASH_REQUIRED||aeState==CONTROL_AE_STATE_PRECAPTURE){
                        mState = STATE_WATTING_LOCK_AE;
                        lockAE();
                    }*/
                    aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    System.out.println("afState:" + afState);
                    System.out.println("aeState:" + aeState);
                    if ((aeState == CONTROL_AE_STATE_CONVERGED||aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) && (afState == CONTROL_AF_STATE_NOT_FOCUSED_LOCKED || afState == CONTROL_AF_STATE_FOCUSED_LOCKED)) {
                        //表示对焦完成,以及AE收敛完成
                        lockAE();
                    }
                    break;
                case STATE_WAITING_NON_PRECAPTURE:
                    Integer aeFinalState = result.get(CaptureResult.CONTROL_AE_STATE);
                    System.out.println("不断尝试锁定AE中");
                    System.out.println(aeFinalState);
                    mState=STATE_PICTURE_TAKEN;
                    //这里就不进行AE的锁定了,不锁定更像日常使用
                    captureStillPicture();
                    /*if (aeFinalState == null || aeFinalState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
                        mState = STATE_PICTURE_TAKEN;
                        System.out.println("锁定成功");
                        captureStillPicture();
                    }*/
                    break;
            }
        }
    };

    //拍照
    private void captureStillPicture() {
        CaptureRequest.Builder captureRequest = null;
        try {
            captureRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        captureRequest.addTarget(jpegImageReader.getSurface());
        captureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        captureRequest.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(myOrientoinListener.angle));
        captureRequest.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
        captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
        //设置AE模式
        changeAEMode(captureRequest);
        try {
            mCaptureSession.capture(captureRequest.build(), new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);
                    //mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.FALSE);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
                    try {
                        session.capture(mPreviewRequestBuilder.build(), null, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_AUTO);
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
                    mState = STATE_PREVIEW;
                    try {
                        session.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);

                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    //锁定AE状态
    private void lockAE() {
        mState = STATE_WAITING_NON_PRECAPTURE;
        //锁定AE
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
        System.out.println("锁定AE");
        try {
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void runPrecaptureSequence() {
        try {
            //开始设置trigger,AE跟AF同时开始trigger
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
            mState = STATE_WAITING_PRECAPTURE;
            System.out.println("开始预打闪");
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值