Home | History | Annotate | Download | only in zsl
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.one.v2.photo.zsl;
     18 
     19 import android.hardware.camera2.CaptureResult;
     20 import android.hardware.camera2.TotalCaptureResult;
     21 
     22 import com.android.camera.async.Updatable;
     23 import com.android.camera.debug.Log;
     24 import com.android.camera.debug.Logger;
     25 import com.android.camera.one.v2.camera2proxy.CaptureRequestProxy;
     26 import com.android.camera.one.v2.camera2proxy.CaptureResultProxy;
     27 import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy;
     28 import com.google.common.base.Objects;
     29 import com.google.common.base.Preconditions;
     30 import com.google.common.base.Predicate;
     31 
     32 import java.util.List;
     33 import java.util.concurrent.atomic.AtomicBoolean;
     34 
     35 import javax.annotation.Nonnull;
     36 import javax.annotation.Nullable;
     37 import javax.annotation.ParametersAreNonnullByDefault;
     38 
     39 /**
     40  * Like {@link AcceptableZslImageFilter}, but determines whether or not to
     41  * filter ZSL images by AE convergence based on the most-recent converged AE
     42  * result. This enables an optimization in which pictures can be taken with zero
     43  * shutter lag when flash is AUTO even if AE is searching.
     44  * <p>
     45  * For example, when flash is AUTO, we can only capture images via the ZSL
     46  * buffer if we know that flash is not required. We know that flash is not
     47  * required when CONTROL_AE_STATE == CONTROL_AE_STATE_CONVERGED. However, when
     48  * the AE system is scanning, we do not know if flash is required. So, instead
     49  * of waiting until it converges, we can cache the most recent result and allow
     50  * capturing an image instantly.
     51  * <p>
     52  * Note that this optimization presents a trade-off between speed and
     53  * quality/accuracy. For example, if a user moves the camera from a bright scene
     54  * to a dark scene and tries to immediately take a picture before AE has
     55  * converged, then the flash may not fire. However, it enables faster capture if
     56  * the user moves the camera from a bright scene to another bright scene with a
     57  * different level of illumination, which would not otherwise require flash.
     58  */
     59 @ParametersAreNonnullByDefault
     60 public final class AutoFlashZslImageFilter implements Predicate<TotalCaptureResultProxy>,
     61         Updatable<CaptureResultProxy> {
     62     private final Logger mLog;
     63     private final AcceptableZslImageFilter mDefaultFilter;
     64 
     65     private AtomicBoolean mRequireAEConvergence;
     66     private long mLastFrameNumber;
     67 
     68     private AutoFlashZslImageFilter(Logger.Factory logFactory,
     69             AcceptableZslImageFilter defaultFilter) {
     70         mDefaultFilter = defaultFilter;
     71         mLog = logFactory.create(new Log.Tag("AutoFlashZslImgFltr"));
     72         mRequireAEConvergence = new AtomicBoolean(true);
     73         mLastFrameNumber = -1;
     74     }
     75 
     76     /**
     77      * Wraps a TotalCaptureResult, converting
     78      * CaptureResult.CONTROL_AE_STATE_SEARCHING into
     79      * CaptureResult.CONTROL_AE_STATE_CONVERGED.
     80      */
     81     private static class AEConvergedTotalCaptureResult implements TotalCaptureResultProxy {
     82         private final TotalCaptureResultProxy mDelegate;
     83 
     84         public AEConvergedTotalCaptureResult(TotalCaptureResultProxy delegate) {
     85             mDelegate = delegate;
     86         }
     87 
     88         @Nullable
     89         @Override
     90         public <T> T get(CaptureResult.Key<T> key) {
     91             if (key == TotalCaptureResult.CONTROL_AE_STATE) {
     92                 Integer aeState = (Integer) mDelegate.get(key);
     93                 if (Objects.equal(aeState, CaptureResult.CONTROL_AE_STATE_SEARCHING)) {
     94                     return (T) ((Integer) CaptureResult.CONTROL_AE_STATE_CONVERGED);
     95                 }
     96             }
     97             return mDelegate.get(key);
     98         }
     99 
    100         @Nonnull
    101         @Override
    102         public List<CaptureResult.Key<?>> getKeys() {
    103             return mDelegate.getKeys();
    104         }
    105 
    106         @Nonnull
    107         @Override
    108         public CaptureRequestProxy getRequest() {
    109             return mDelegate.getRequest();
    110         }
    111 
    112         @Override
    113         public long getFrameNumber() {
    114             return mDelegate.getFrameNumber();
    115         }
    116 
    117         @Override
    118         public int getSequenceId() {
    119             return mDelegate.getSequenceId();
    120         }
    121 
    122         @Nonnull
    123         @Override
    124         public List<CaptureResultProxy> getPartialResults() {
    125             return mDelegate.getPartialResults();
    126         }
    127     }
    128 
    129     public static AutoFlashZslImageFilter create(Logger.Factory logFactory,
    130             boolean requireAFConvergence) {
    131         return new AutoFlashZslImageFilter(
    132                 logFactory,
    133                 new AcceptableZslImageFilter(requireAFConvergence, /* aeConvergence */true));
    134     }
    135 
    136     @Override
    137     public boolean apply(TotalCaptureResultProxy totalCaptureResultProxy) {
    138         if (!mRequireAEConvergence.get()) {
    139             // If AE was previously converged, wrap the metadata to appear as if AE is currently
    140             // converged.
    141             totalCaptureResultProxy = new AEConvergedTotalCaptureResult(totalCaptureResultProxy);
    142         }
    143         return mDefaultFilter.apply(totalCaptureResultProxy);
    144     }
    145 
    146     @Override
    147     public void update(@Nonnull CaptureResultProxy captureResult) {
    148         if (captureResult.getFrameNumber() > mLastFrameNumber) {
    149             Integer aeState = captureResult.get(CaptureResult.CONTROL_AE_STATE);
    150             if (aeState != null) {
    151                 if (aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED) {
    152                     boolean previousValue = mRequireAEConvergence.getAndSet(true);
    153                     if (previousValue != true) {
    154                         // Only log changes
    155                         mLog.i("Flash required");
    156                     }
    157                 } else if (aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
    158                     boolean previousValue = mRequireAEConvergence.getAndSet(false);
    159                     if (previousValue != false) {
    160                         // Only log changes
    161                         mLog.i("Flash not required");
    162                     }
    163                 }
    164                 mLastFrameNumber = captureResult.getFrameNumber();
    165             }
    166         }
    167     }
    168 }
    169