手机Camera的前后摄闪光灯虽然是同一个feature,但是从软硬件任意角度来讲,都有着很大的区别。后摄闪光灯是有专门的物理空间支持的,就是手机的手电筒物理控件,当后摄开启闪光灯拍照时候,会触发俩次打闪,第一次会给200mA左右的脉冲电流,称为预闪,为的是获取当前环境下的亮度等信息;第二次会给800mA甚至更强的脉冲电流,称为主闪。反观前摄闪光啥也没有,仅仅靠屏幕补光来实现效果,视觉效果就是一张糊上去的白色的View。下面从代码的角度来研究一下闪光灯效果的实现。

1.后摄闪光应用层控件

应用层简单点就是添加闪光灯控件,下发闪光灯不同模式下相对应的tag,拍照时唤起底层的俩次打闪并进行处理。

@Overridepublic void init(IApp app,ICameraContext cameraContext,ISettingManager.SettingController settingController) {super.init(app, cameraContext, settingController);String value = mDataStore.getValue(FLASH_KEY, FLASH_DEFAULT_VALUE, getStoreScope());setValue(value);if (mFlashViewController == null) {mFlashViewController = new FlashViewController(this, app);}mStatusMonitor.registerValueChangedListener(KEY_CSHOT, mStatusChangeListener);// [Add for CCT tool] Receive keycode and enable/disable flash @{mKeyEventListener = mFlashViewController.getKeyEventListener();mApp.registerKeyEventListener(mKeyEventListener, IApp.DEFAULT_PRIORITY);IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);mActivity.registerReceiver(mBatteryLevelReceiver, filter);// @}}@Overridepublic void addViewEntry() {//前摄闪光灯模块用其他的控件处理if (!FRONT_CAMERA_ID.equals(((CameraAppUI)mAppUi).getCurrentCameraId())) {mFlashViewController.addQuickSwitchIcon();//滤镜模式下的闪光灯互斥处理if(isFilterOn()) {mFlashViewController.showQuickSwitchIcon(false);} else {mFlashViewController.showQuickSwitchIcon(getEntryValues().size() > 1);}//低电量情况闪光灯灰置处理if (mApp.hasLowBattery()) {onFlashValueChanged(FLASH_OFF_VALUE);if (mFlashViewController.mFlashEntryView != null) {mFlashViewController.mFlashEntryView.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);}} else {if (mFlashViewController.mFlashEntryView != null) {mFlashViewController.mFlashEntryView.setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY);}}} else {mFlashViewController.removeQuickSwitchIcon();mFlashViewController.showQuickSwitchIcon(false);}}private ImageView initFlashEntryView() {Activity activity = mApp.getActivity();//相机界面显示的闪光灯图标RotateImageView view = (RotateImageView) activity.getLayoutInflater().inflate(R.layout.flash_icon, null);view.setOnClickListener(mFlashEntryListener);//点击闪光灯图标显示出的隐藏选项mFlashIndicatorView = (RotateImageView) activity.getLayoutInflater().inflate(R.layout.flash_indicator, null);return view;}/*** This listener used to monitor the flash quick switch icon click item.*/private final View.OnClickListener mFlashEntryListener = new View.OnClickListener() {public void onClick(View view) {//低电量不可点击final int lowBatteryWarningLevel = CameraUtil.getLowBatteryLevel(mApp);if (mFlash.barrtyLevel <= lowBatteryWarningLevel) {OnScreenHint.makeText(mApp.getActivity(), mApp.getActivity().getString(R.string.low_battery_disable_flash)).showToast();updateFlashEntryView(FLASH_OFF_VALUE);mFlash.onFlashValueChanged(FLASH_OFF_VALUE);mFlashEntryView.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);return;}//支持的闪光灯模式<=1不可点击if (mFlash.getEntryValues().size() <= 1) {return;}//点击闪光灯图标的处理if (mFlash.getEntryValues().size() > FLASH_ENTRY_LIST_SWITCH_SIZE) {initializeFlashChoiceView();updateChoiceView();//显示闪光灯隐藏选项mApp.getAppUi().showQuickSwitcherOption(mOptionLayout);} else {String value = mFlash.getEntryValues().get(FLASH_ENTRY_LIST_INDEX_0);if (value.equals(mFlash.getValue())) {value = mFlash.getEntryValues().get(FLASH_ENTRY_LIST_INDEX_1);}updateFlashEntryView(value);// Flash indicator no need to show now,would be enable later// updateFlashIndicator(value);mFlash.onFlashValueChanged(value);}}};//闪光灯隐藏选项的点击事件处理,支持on/auto/off三种选项private View.OnClickListener mFlashChoiceViewListener = new View.OnClickListener() {@Overridepublic void onClick(View view) {String value = "";if (mFlashAutoIcon == view) {value = FLASH_AUTO_VALUE;} else if (mFlashOnIcon == view) {value = FLASH_ON_VALUE;} else {value = FLASH_OFF_VALUE;}mApp.getAppUi().setHideQuickSwitchOptionByUser(true);mApp.getAppUi().hideQuickSwitcherOption();updateFlashEntryView(value);// Flash indicator no need to show now,would be enable later// updateFlashIndicator(value);mFlash.onFlashValueChanged(value);}};

应用层的UI设计没有技术含量,关键在于应用层和HAL之前的tag下发管理这一块,简单中隐藏着一丝不简单,老是让你有着被干扰的不痛快的感觉。

@Overridepublic void configCaptureRequest(CaptureRequest.Builder captureBuilder) {if (captureBuilder == null) {LogHelper.d(TAG, "[configCaptureRequest] captureBuilder is null");return;}if (mIsFlashSupported || mIsPanelFlashSupported) {updateFlashMode();captureBuilder.set(CaptureRequest.FLASH_MODE, mFlashMode);LogHelper.i(TAG, "[configCaptureRequest], mFlashMode = " + mFlashMode);}}private void updateFlashMode() {if (Flash.FLASH_ON_VALUE.equalsIgnoreCase(mFlash.getValue())) {if (mNeedChangeFlashModeToTorch ||mFlash.getCurrentModeType() == ICameraMode.ModeType.VIDEO) {mFlashMode = CameraMetadata.FLASH_MODE_TORCH;return;}// AE mode -> ON_ALWAYS_FLASH, flash mode value doesn't affectmFlashMode = CameraMetadata.FLASH_MODE_OFF;return;}if (Flash.FLASH_AUTO_VALUE.equalsIgnoreCase(mFlash.getValue())) {if (mNeedChangeFlashModeToTorch) {mFlashMode = CameraMetadata.FLASH_MODE_TORCH;LogHelper.d(TAG, "[updateFlashMode] change flash mode to torch");return;}// AE mode -> ON_AUTO_FLASH, flash mode value doesn't affectmFlashMode = CameraMetadata.FLASH_MODE_OFF;return;}// flash -> off, must need AE mode -> onmFlashMode = CameraMetadata.FLASH_MODE_OFF;}

在应用层对Flash的Tag管理中需要特别注意注释里面的AE mode -> ON_ALWAYS_FLASH 以及 AE mode -> ON_AUTO_FLASH, 有一说一,我对MTK原生Camera apk 里面长按屏幕触发AE/AF锁模式,保持对焦以及聚光状态的feature理解不太深,一直没有明白为什么触发AE mode要强行僭越Flash的管控机制,一直保持Flash开启状态;真心深恶痛觉以及有点烦这个设计,你对焦你聚光你就聚呗,一定时间的闪光灯开启然后去拍照是可以理解的,不过往往是提示框消失很久了,AE mode的状态还是保持长按触发不改变,导致用户拍照时候即使闪光灯未开启也有闪光灯效果。我认为,AE mode并不是老大,是否打闪的权利完全由Flash自己主宰,所以经我手的Camera apk对于这方面Flash和AE的管控, 我都给改了。

修改文件:ExposureCaptureRequestConfigure.java

private void updateAeMode() {if (mAEMode == CameraMetadata.CONTROL_AE_MODE_ON_EXTERNAL_FLASH) {return;}setOriginalAeMode();}private void setOriginalAeMode() {String flashValue = mExposure.getCurrentFlashValue();if (FLASH_ON_VALUE.equalsIgnoreCase(flashValue)) {if (mNeedChangeFlashModeToTorch ||mExposure.getCurrentModeType() == ICameraMode.ModeType.VIDEO) {mAEMode = CameraMetadata.CONTROL_AE_MODE_ON;return;}//AE mode强制Flash效果mAEMode = CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH;// AE mode -> ON_ALWAYS_FLASH, flash mode value doesn't affectreturn;}if (FLASH_AUTO_VALUE.equalsIgnoreCase(flashValue)) {if (mNeedChangeFlashModeToTorch) {mAEMode = CameraMetadata.CONTROL_AE_MODE_ON;return;}//AE mode强制Flash效果AE mode -> ON_AUTO_FLASH, flash mode value doesn't affect//mAEMode = CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH;return;}// flash -> off, must need AE mode -> onmAEMode = CameraMetadata.CONTROL_AE_MODE_ON;}

2.后摄闪光灯拍照之后的底层处理

    时间关系,这一部分我就不拎出来仔细讲了,之后应该会再出一版Flash有关的内容讲一下开启闪光灯功能底层拍照流程走的代码,以及为啥AE mode就能主宰Flash Mode的底层设定;甚至可能会通过代码研究一下Camera Tunning那一块根据预闪获得的环境参数,配合一定算法咋么调整拍出来的照片的RGB参数。今天就先根据一份log看一下底层的处理。

evaluteCaptureSetting是根据应用层下发的CaptureRequest得到的拍照要处理的feature;strategyMultiFramePlugin是拍照处理哥哥响应的多帧feature,很多feature并不是简单的拍一张图片,涉及到多帧图像的处理;updateCaptureDummyFrames这边就是拍照对多帧图片的一个处理,post了几张之类的,isFlashOn的标志位就是HAL层直接根据应用层下发的Flash mode、AE mode得到的相对应的值。log里面所有显示的内容都是可以通过代码来层层获取相对的行为以及处理方法。庞大而精巧,希望以后的时间里能抽丝剥茧的将这些都拎出来晒晒。

3.前摄闪光灯补光处理

应用层对前摄闪光灯的控件管理类似后摄,由于前摄补光功能完全是由应用层完成的,所以不涉及tag的下发,应用层要简单很多。主要内容就是补光功能,代码如下:

 @Overrideprotected boolean doShutterButtonClick() {if (storageReady && isDeviceReady && mIsResumed) {//开起补光动画,白色的mCoreView//trigger capture animationstartCaptureAnimation();updateModeDeviceState(MODE_DEVICE_STATE_CAPTURING);mIDeviceController.updateGSensorOrientation(mIApp.getGSensorOrientation());if ("on".equals(getFrontFlashValue()) && mIApp.getAppUi().getCurrentCameraId().equals("1")) {mApp.getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {((CameraActivity)mIApp).setAlpha(0.8f);}});//开始拍照抓取补光效果的帧takeFrontFlashPicture();} else {mIDeviceController.takePicture(this);}}return true;}public void animationStart(AnimationType type, IAppUi.AnimationData data) {LogHelper.d(TAG, "Start animation type: " + type);switch (type) {case TYPE_CAPTURE:if ("on".equals(getFrontFlashValue()) && mAppUI.getCurrentCameraId().equals("1") && mAppUI.getVideoState() != VideoState.STATE_RECORDING) {if("Z3".equals(MODEL) || "Z4".equals(MODEL)){mCoverView.setBackgroundColor(Color.parseColor("#fff0e6"));}else{//将View背景绘成白色,便于补光mCoverView.setBackgroundColor(Color.WHITE);}} else {mCoverView.setBackgroundColor(Color.BLACK);}mCoverView.setVisibility(View.VISIBLE);//开始补光的动作playCaptureAnimation();break;default:break;}}private void playCaptureAnimation() {LogHelper.d(TAG, "playCaptureAnimation +");AnimatorSet captureAnimation =(AnimatorSet) AnimatorInflater.loadAnimator(mApp.getActivity(),R.animator.cature_anim);if ("on".equals(getFrontFlashValue()) && mAppUI.getCurrentCameraId().equals("1") && mAppUI.getVideoState() != VideoState.STATE_RECORDING) {captureAnimation =(AnimatorSet) AnimatorInflater.loadAnimator(mApp.getActivity(),R.animator.cature_anim_fill);}captureAnimation.setTarget(mCoverView);//补光动作结束事件的监听captureAnimation.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);mCoverView.setVisibility(View.GONE);mApp.getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {((CameraActivity)mApp).setAlpha(1.0f);}});}});captureAnimation.start();LogHelper.d(TAG, "playCaptureAnimation -");}

Camera:前后闪光灯相关推荐

  1. camera打开闪光灯页面崩溃 android,Android打开闪光灯关键代码

    在AndroidManifest中注册相应的权限: 打开闪光灯关键代码: Camera  camera = Camera.open(); camera.startPreview(); paramete ...

  2. 基于opencv的相机之camera切换/闪光灯/边缘模式/分辨率(二)

    简介 简而言之,就是在之前的最初基本布局,继续完善了camera前后摄切换.闪光灯开关,以及添加了边缘预览模式,以及预览分辨率设置功能. 边缘模式 原理讲解 简单的说,就是利用ndk,使用opencv ...

  3. Android之打开闪光灯关键代码

    在AndroidManifest中注册相应的权限: <uses-permission android:name="android.permission.FLASHLIGHT" ...

  4. 【Android 学习】之二维码扫描开发(闪光灯功能)

    .............................................................................. Android二维码扫描我们可以调用Zin ...

  5. android自定义相机打开闪光灯,Android 照相机(闪光灯,切换摄像头)

    1.开启关闭闪光灯 /** * 通过设置Camera打开闪光灯 */ public synchronized void turnLightOn() { if (camera == null) { re ...

  6. android 打开闪光灯

    在android中打开闪光灯的方法有两种,一种是获取硬件服务,通过反射的方式来操作闪光灯.另外一种是获得Camera对象,通过设置Camera的参数来操作闪光灯.一下是一个操作闪光灯的工具类:实现了两 ...

  7. Android如何打开闪光灯

    在android中打开闪光灯的方法有两种,一种是获取硬件服务,通过反射的方式来操作闪光灯.另外一种是获得Camera对象,通过设置Camera的参数来操作闪光灯.一下是一个操作闪光灯的工具类:实现了两 ...

  8. 【微信小程序】闪光灯(闪烁效果)

    目前来说,微信小程序本身的开发文档对于camera的闪光灯只提供了on和off两种状态,若想要实现闪烁的效果还是需要我们自己实现. 首先,我们先查阅微信小程序的开发文档,找到组件中camera的相关文 ...

  9. 【高通SDM660平台】(1) --- Camera 驱动 Bringup Guide

    [高通SDM660平台]Camera 驱动 Bringup Guide 一.Kernel 代码移植 1. DTS 文件配置 1.1 sdm660.dtsi 1.2 sdm660-camera.dtsi ...

最新文章

  1. 新一代测序技术Sparc
  2. VMware Mac版本漏洞可任意执行恶意代码
  3. 网站品牌词指数提升的四大方法
  4. elasticsearch之查询扩展
  5. 四.Android adb命令(持续更新...)
  6. 通过PROC信息调节TCP窗口
  7. reactjs 全局状态管理:redux的组成
  8. LINQ to SQL学习的几个问题
  9. [渝粤教育] 西南科技大学 经济法概论 在线考试复习资料2021版(3)
  10. centos配置单网卡双IP
  11. 每天只睡 4 小时!大佬们都这么拼吗?
  12. 【原创手写笔记】面试准备,关于决策树算法你需要知道的那些
  13. paip.陕北方言 广东方言的不同单字 1千高频字
  14. web前端课程设计源码大全(HTML+CSS+JS)
  15. 百度没有柳传志,联想没有李彦宏
  16. FreeBSD+gnome3详细安装指南
  17. pycharm运行python程序没有解释器怎么办
  18. ORB词袋特征提取和匹配
  19. 目标跟踪系列三:ECO: Efficient Convolution Operators for Tracking(2016年11月)
  20. Migrando电子商务可以实现Iluria para o Shopify(Python的标准)

热门文章

  1. RTL8197F/RTL8812F WiFi设置为WPA3加密手机提示拒绝连接问题解决方案
  2. redis+Python实现小型动态IP池的搭建,仅需90行代码
  3. 龙珠游戏-博弈之斐波那契数列
  4. python海龟图画龙珠_DeepOps的Python小笔记-天池龙珠计划-Python训练营-Task 02:DAY4
  5. 化工企业双重预防体系数字化综合管理系统
  6. 武林外传之勇夺金掌柜 【安卓游戏】
  7. 天猫淘宝越来越难做了,为什么不考虑下跨境电商?
  8. 服务器怎么买,腾讯云服务器购买三种流程介绍
  9. 感冒初期试试食疗方 盲目用药伤脾胃
  10. 一个Java画图板程序的设计