• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.mediaframeworktest.helpers;
18 
19 import com.android.ex.camera2.pos.AutoFocusStateMachine;
20 import com.android.ex.camera2.pos.AutoFocusStateMachine.AutoFocusStateListener;
21 
22 import android.hardware.camera2.CameraAccessException;
23 import android.hardware.camera2.CameraCaptureSession;
24 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
25 import android.hardware.camera2.CameraCharacteristics;
26 import android.hardware.camera2.CameraDevice;
27 import android.hardware.camera2.CaptureRequest;
28 import android.hardware.camera2.CaptureResult;
29 import android.hardware.camera2.TotalCaptureResult;
30 import android.hardware.camera2.params.MeteringRectangle;
31 import android.os.Handler;
32 import android.util.Log;
33 import android.view.Surface;
34 
35 /**
36  * A focuser utility class to assist camera to do auto focus.
37  * <p>
38  * This class need create repeating request and single request to do auto focus.
39  * The repeating request is used to get the auto focus states; the single
40  * request is used to trigger the auto focus. This class assumes the camera device
41  * supports auto-focus. Don't use this class if the camera device doesn't have focuser
42  * unit.
43  * </p>
44  */
45 /**
46  * (non-Javadoc)
47  * @see android.hardware.camera2.cts.helpers.Camera2Focuser
48  */
49 public class Camera2Focuser implements AutoFocusStateListener {
50     private static final String TAG = "Focuser";
51     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
52 
53     private final AutoFocusStateMachine mAutoFocus = new AutoFocusStateMachine(this);
54     private final Handler mHandler;
55     private final AutoFocusListener mAutoFocusListener;
56     private final CameraDevice mCamera;
57     private final CameraCaptureSession mSession;
58     private final Surface mRequestSurface;
59     private final StaticMetadata mStaticInfo;
60 
61     private int mAfRun = 0;
62     private MeteringRectangle[] mAfRegions;
63     private boolean mLocked = false;
64     private boolean mSuccess = false;
65     private CaptureRequest.Builder mRepeatingBuilder;
66 
67     /**
68      * The callback interface to notify auto focus result.
69      */
70     public interface AutoFocusListener {
71         /**
72          * This callback is called when auto focus completes and locked.
73          *
74          * @param success true if focus was successful, false if otherwise
75          */
onAutoFocusLocked(boolean success)76         void onAutoFocusLocked(boolean success);
77     }
78 
79     /**
80      * Construct a focuser object, with given capture requestSurface, listener
81      * and handler.
82      * <p>
83      * The focuser object will use camera and requestSurface to submit capture
84      * request and receive focus state changes. The {@link AutoFocusListener} is
85      * used to notify the auto focus callback.
86      * </p>
87      *
88      * @param camera The camera device associated with this focuser
89      * @param session The camera capture session associated with this focuser
90      * @param requestSurface The surface to issue the capture request with
91      * @param listener The auto focus listener to notify AF result
92      * @param staticInfo The CameraCharacteristics of the camera device
93      * @param handler The handler used to post auto focus callbacks
94      * @throws CameraAccessException
95      */
Camera2Focuser(CameraDevice camera, CameraCaptureSession session, Surface requestSurface, AutoFocusListener listener, CameraCharacteristics staticInfo, Handler handler)96     public Camera2Focuser(CameraDevice camera, CameraCaptureSession session, Surface requestSurface,
97             AutoFocusListener listener, CameraCharacteristics staticInfo, Handler handler)
98             throws CameraAccessException {
99         if (camera == null) {
100             throw new IllegalArgumentException("camera must not be null");
101         }
102         if (session == null) {
103             throw new IllegalArgumentException("session must not be null");
104         }
105         if (listener == null) {
106             throw new IllegalArgumentException("listener must not be null");
107         }
108         if (handler == null) {
109             throw new IllegalArgumentException("handler must not be null");
110         }
111         if (requestSurface == null) {
112             throw new IllegalArgumentException("requestSurface must not be null");
113         }
114         if (staticInfo == null) {
115             throw new IllegalArgumentException("staticInfo must not be null");
116         }
117 
118         mCamera = camera;
119         mSession = session;
120         mRequestSurface = requestSurface;
121         mAutoFocusListener = listener;
122         mStaticInfo = new StaticMetadata(staticInfo,
123                 StaticMetadata.CheckLevel.ASSERT, /*collector*/null);
124         mHandler = handler;
125 
126         if (!mStaticInfo.hasFocuser()) {
127             throw new IllegalArgumentException("this camera doesn't have a focuser");
128         }
129 
130         /**
131          * Begin by always being in passive auto focus.
132          */
133         cancelAutoFocus();
134     }
135 
136     @Override
onAutoFocusSuccess(CaptureResult result, boolean locked)137     public synchronized void onAutoFocusSuccess(CaptureResult result, boolean locked) {
138         mSuccess = true;
139         mLocked = locked;
140 
141         if (locked) {
142             dispatchAutoFocusStatusLocked(/*success*/true);
143         }
144     }
145 
146     @Override
onAutoFocusFail(CaptureResult result, boolean locked)147     public synchronized void onAutoFocusFail(CaptureResult result, boolean locked) {
148         mSuccess = false;
149         mLocked = locked;
150 
151         if (locked) {
152             dispatchAutoFocusStatusLocked(/*success*/false);
153         }
154     }
155 
156     @Override
onAutoFocusScan(CaptureResult result)157     public synchronized void onAutoFocusScan(CaptureResult result) {
158         mSuccess = false;
159         mLocked = false;
160     }
161 
162     @Override
onAutoFocusInactive(CaptureResult result)163     public synchronized void onAutoFocusInactive(CaptureResult result) {
164         mSuccess = false;
165         mLocked = false;
166     }
167 
168     /**
169      * Start a active auto focus scan based on the given regions.
170      *
171      * <p>This is usually used for touch for focus, it can make the auto-focus converge based
172      * on some particular region aggressively. But it is usually slow as a full active scan
173      * is initiated. After the auto focus is converged, the {@link cancelAutoFocus} must be called
174      * to resume the continuous auto-focus.</p>
175      *
176      * @param afRegions The AF regions used by focuser auto focus, full active
177      * array size is used if afRegions is null.
178      * @throws CameraAccessException
179      */
touchForAutoFocus(MeteringRectangle[] afRegions)180     public synchronized void touchForAutoFocus(MeteringRectangle[] afRegions)
181             throws CameraAccessException {
182         startAutoFocusLocked(/*active*/true, afRegions);
183     }
184 
185     /**
186      * Start auto focus scan.
187      * <p>
188      * Start an auto focus scan if it was not done yet. If AF passively focused,
189      * lock it. If AF is already locked, return. Otherwise, initiate a full
190      * active scan. This is suitable for still capture: focus should need to be
191      * accurate, but the AF latency also need to be as short as possible.
192      * </p>
193      *
194      * @param afRegions The AF regions used by focuser auto focus, full active
195      *            array size is used if afRegions is null.
196      * @throws CameraAccessException
197      */
startAutoFocus(MeteringRectangle[] afRegions)198     public synchronized void startAutoFocus(MeteringRectangle[] afRegions)
199             throws CameraAccessException {
200         startAutoFocusLocked(/*forceActive*/false, afRegions);
201     }
202 
203     /**
204      * Cancel ongoing auto focus, unlock the auto-focus if it was locked, and
205      * resume to passive continuous auto focus.
206      *
207      * @throws CameraAccessException
208      */
cancelAutoFocus()209     public synchronized void cancelAutoFocus() throws CameraAccessException {
210         mSuccess = false;
211         mLocked = false;
212 
213         // reset the AF regions:
214         setAfRegions(null);
215 
216         // Create request builders, the af regions are automatically updated.
217         mRepeatingBuilder = createRequestBuilder();
218         CaptureRequest.Builder requestBuilder = createRequestBuilder();
219         mAutoFocus.setPassiveAutoFocus(/*picture*/true, mRepeatingBuilder);
220         mAutoFocus.unlockAutoFocus(mRepeatingBuilder, requestBuilder);
221         CaptureCallback listener = createCaptureListener();
222         mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler);
223         mSession.capture(requestBuilder.build(), listener, mHandler);
224     }
225 
226     /**
227      * Get current AF mode.
228      * @return current AF mode
229      * @throws IllegalStateException if there auto focus is not running.
230      */
getCurrentAfMode()231     public synchronized int getCurrentAfMode() {
232         if (mRepeatingBuilder == null) {
233             throw new IllegalStateException("Auto focus is not running, unable to get AF mode");
234         }
235 
236         return mRepeatingBuilder.get(CaptureRequest.CONTROL_AF_MODE);
237     }
238 
startAutoFocusLocked( boolean forceActive, MeteringRectangle[] afRegions)239     private void startAutoFocusLocked(
240             boolean forceActive, MeteringRectangle[] afRegions) throws CameraAccessException {
241 
242         setAfRegions(afRegions);
243         mAfRun++;
244 
245         // Create request builders, the af regions are automatically updated.
246         mRepeatingBuilder = createRequestBuilder();
247         CaptureRequest.Builder requestBuilder = createRequestBuilder();
248         if (forceActive) {
249             startAutoFocusFullActiveLocked();
250         } else {
251             // Not forcing a full active scan. If AF passively focused, lock it. If AF is already
252             // locked, return. Otherwise, initiate a full active scan.
253             if (mSuccess && mLocked) {
254                 dispatchAutoFocusStatusLocked(/*success*/true);
255                 return;
256             } else if (mSuccess) {
257                 mAutoFocus.lockAutoFocus(mRepeatingBuilder, requestBuilder);
258                 CaptureCallback listener = createCaptureListener();
259                 mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler);
260                 mSession.capture(requestBuilder.build(), listener, mHandler);
261             } else {
262                 startAutoFocusFullActiveLocked();
263             }
264         }
265     }
266 
startAutoFocusFullActiveLocked()267     private void startAutoFocusFullActiveLocked() throws CameraAccessException {
268         // Create request builders, the af regions are automatically updated.
269         mRepeatingBuilder = createRequestBuilder();
270         CaptureRequest.Builder requestBuilder = createRequestBuilder();
271         mAutoFocus.setActiveAutoFocus(mRepeatingBuilder, requestBuilder);
272         if (mRepeatingBuilder.get(CaptureRequest.CONTROL_AF_TRIGGER)
273                 != CaptureRequest.CONTROL_AF_TRIGGER_IDLE) {
274             throw new AssertionError("Wrong trigger set in repeating request");
275         }
276         if (requestBuilder.get(CaptureRequest.CONTROL_AF_TRIGGER)
277                 != CaptureRequest.CONTROL_AF_TRIGGER_START) {
278             throw new AssertionError("Wrong trigger set in queued request");
279         }
280         mAutoFocus.resetState();
281 
282         CaptureCallback listener = createCaptureListener();
283         mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler);
284         mSession.capture(requestBuilder.build(), listener, mHandler);
285     }
286 
dispatchAutoFocusStatusLocked(final boolean success)287     private void dispatchAutoFocusStatusLocked(final boolean success) {
288         mHandler.post(new Runnable() {
289             @Override
290             public void run() {
291                 mAutoFocusListener.onAutoFocusLocked(success);
292             }
293         });
294     }
295 
296     /**
297      * Create request builder, set the af regions.
298      * @throws CameraAccessException
299      */
createRequestBuilder()300     private CaptureRequest.Builder createRequestBuilder() throws CameraAccessException {
301         CaptureRequest.Builder requestBuilder =
302                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
303 
304         requestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, mAfRegions);
305         requestBuilder.addTarget(mRequestSurface);
306 
307         return requestBuilder;
308     }
309 
310     /**
311      * Set AF regions, fall back to default region if afRegions is null.
312      *
313      * @param afRegions The AF regions to set
314      * @throws IllegalArgumentException if the region is malformed (length is 0).
315      */
setAfRegions(MeteringRectangle[] afRegions)316     private void setAfRegions(MeteringRectangle[] afRegions) {
317         if (afRegions == null) {
318             setDefaultAfRegions();
319             return;
320         }
321         // Throw IAE if AF regions are malformed.
322         if (afRegions.length == 0) {
323             throw new IllegalArgumentException("afRegions is malformed, length: 0");
324         }
325 
326         mAfRegions = afRegions;
327     }
328 
329     /**
330      * Set default AF region to full active array size.
331      */
setDefaultAfRegions()332     private void setDefaultAfRegions() {
333         // Initialize AF regions with all zeros, meaning that it is up to camera device to device
334         // the regions used by AF.
335         mAfRegions = new MeteringRectangle[] {
336                 new MeteringRectangle(0, 0, 0, 0, MeteringRectangle.METERING_WEIGHT_DONT_CARE)};
337     }
createCaptureListener()338     private CaptureCallback createCaptureListener() {
339 
340         int thisAfRun;
341         synchronized (this) {
342             thisAfRun = mAfRun;
343         }
344 
345         final int finalAfRun = thisAfRun;
346 
347         return new CaptureCallback() {
348             private long mLatestFrameCount = -1;
349 
350             @Override
351             public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
352                     CaptureResult result) {
353                 // In case of a partial result, send to focuser if necessary
354                 // 3A fields are present
355                 if (result.get(CaptureResult.CONTROL_AF_STATE) != null &&
356                         result.get(CaptureResult.CONTROL_AF_MODE) != null) {
357                     if (VERBOSE) {
358                         Log.v(TAG, "Focuser - got early AF state");
359                     }
360 
361                     dispatchToFocuser(result);
362                 }
363             }
364 
365             @Override
366             public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
367                     TotalCaptureResult result) {
368                     dispatchToFocuser(result);
369             }
370 
371             private void dispatchToFocuser(CaptureResult result) {
372                 int afRun;
373                 synchronized (Camera2Focuser.this) {
374                     // In case of partial results, don't send AF update twice
375                     long frameCount = result.getFrameNumber();
376                     if (frameCount <= mLatestFrameCount) return;
377                     mLatestFrameCount = frameCount;
378 
379                     afRun = mAfRun;
380                 }
381 
382                 if (afRun != finalAfRun) {
383                     if (VERBOSE) {
384                         Log.w(TAG,
385                                 "onCaptureCompleted - Ignoring results from previous AF run "
386                                 + finalAfRun);
387                     }
388                     return;
389                 }
390 
391                 mAutoFocus.onCaptureCompleted(result);
392             }
393         };
394     }
395 }
396