前言

在实现拍照前打闪的时候,主要遇到了两点问题,第一就是平台不同,对于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();}}}//拍照前锁定AFprivate 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();}*///我们这波考虑先看看AEToast.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() {@Overridepublic 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();}}}*///这波先看AEif (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) {//不支持AEmState = 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) {//不支持AEmState = 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() {@Overridepublic 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;//锁定AEmPreviewRequestBuilder.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同时开始triggermPreviewRequestBuilder.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();}}

拍照前打闪的注意事项相关推荐

  1. 羽毛球之双打反手发网前小球后的注意事项

    上次分享了双打如何反手发网前小球,这次主要分享反手发网前小球后的注意事项. 反手发完小球后,身体重心要稍微往前倾,这样利于及时向网前启动,然后以中线为中心,双脚小跳一下启动,双脚同时跨出,同时落地,不 ...

  2. 苹果x来电闪光灯怎么设置_苹果相机网格怎么设置,新iPhone拍照前必须设置?...

    大家在拍照的时候一般都会选用"三分构图法",当使用iPhone进行拍照的时候,我们可以在相机中设置"网格线",这样"三分构图法"就更方便使用 ...

  3. android手机拍照,安卓手机拍照前五名?华为有两款上榜!喜欢拍照的机友看进来!...

    原标题:安卓手机拍照前五名?华为有两款上榜!喜欢拍照的机友看进来! 华为P20 Pro 第一款可拍照手机是华为不久前推出的华为P20 Pro.华为设计师大胆地为这台机器配备了三个后置摄像头,这些摄像头 ...

  4. 计算机组装前的主意事项有,组装电脑前的准备与注意事项

    组装电脑前的准备与注意事项 组装电脑前的准备与注意事项 没有目标不急攒机 攒机首先要明确自己的预算和用途,之所以这两个放在一起说,因为预算基本上就可以决定整机性能了,要想大幅提升整体的性能,预算就得跟 ...

  5. oracle闪回15分钟前,Oracle闪回技术(Flashback)

    闪回技术有闪回表.闪回删除.闪回查询.闪回事务查询.闪回事务.闪回数据库.闪回数据归档.其中,闪回查询.闪回事务查询用来"观察"过去:闪回数据归档并不是一个独立的功能,其功能是扩展 ...

  6. 应届生拿到offer之后的流程_应届生签offer前需要参考的注意事项

    大学毕业生经过重重考验拿到 offer 之后, 下一步要面临的问题就是签约. 而如果有的同 学之前已经跟其它单位签约,现在又想和新单位签约,那么又涉及到一个问题:违约. 下面 给大家讲讲应届生签约最应 ...

  7. 参加web前端学习前需要知道的注意事项

    随着web前端的飞速发展,学习web前端的人员也是越来越多,从目前web前端行业发展形式来看,学习web前端最快最高效的方法就是参加web前端培训了.其实,参加web前端培训是一个循序渐进的过程,那么 ...

  8. ionic2 小米手机拍照选相册 闪退的问题

    1.ionic platform add android@6.3.0 说明: 可能是android 版本的问题 指定版本 如果报错 2.android sdk 说明:可能是sdk版本太高 用24版本 ...

  9. cordova vue ios调用camera拍照保存图片时闪退 iOS11之后

    在配置config.xml时需要添加保存图片的权限 <platform name="ios"><config-file parent="NSCamera ...

最新文章

  1. RedHat Enterprise 5.1下OpenLDAP的配置及PAMNSS的配置
  2. mysql同步出现错误
  3. poj2112 二分最大流+Floyd
  4. 030_jQuery Ajax的get方法
  5. 小手取红色球C语言程序,C语言程序设计例精编.doc
  6. php session修改时间,PHP如何修改SESSION有效时间?
  7. 20180908 2018-2019-2 《密码与安全新技术专题》第3周作业
  8. SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化
  9. WebDriver与浏览器版本对应关系
  10. 【DBSCAN聚类算法原理介绍】
  11. 从快感到成就感:多巴胺vs内啡肽
  12. 删除wmspdmv监控进程-- 背后的眼睛
  13. 7033: Lounge Lizards(lis)
  14. Linux上配置BIP语言编译器及引擎
  15. bzoj1375 双调路径
  16. Zotero+OneDrive多平台在线同步完美解决方案(一):安装配置、云端同步文献数据
  17. python爬虫获取百度贴吧内容
  18. opensll zbar交叉编译(君正平台)
  19. 如何用SPSS进行数据分析?
  20. java之TimeUnit.SECONDS.sleep()详细分析(全)

热门文章

  1. opencv图片旋转90°/-90°/180°
  2. Cadence网表算法
  3. mac用大写键caps lock不显示输入法切换解决
  4. 爱奇艺国内首家PC端上线杜比视界服务 持续打造“影院级体验”
  5. 感量越大抑制频率约低_开关电源电磁兼容进级-EMI传导输入滤波器的设计理论(ED-TEST上海)...
  6. 10000+门店的蜜雪冰城,帮你找回软件赚钱的初心
  7. Godaddy服务器上关于ASP.NET网站建设一些经验 - 防SQL注入攻击(三)
  8. SSM+老年人社区服务平台 毕业设计-附源码211711
  9. 地平线开发者社区真心话大冒险,邀你闯关!
  10. AtCoder Beginner Contest 203(Sponsored by Panasonic)D.Pond