• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 android.hardware.camera2;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.hardware.camera2.utils.HashCodeHelpers;
24 
25 import com.android.internal.camera.flags.Flags;
26 
27 import java.util.concurrent.Executor;
28 
29 /**
30  * A camera capture session that enables access to device-specific camera extensions, which
31  * often use multi-frame bursts and sophisticated post-process algorithms for image capture.
32  *
33  * <p>The capture session will be returned after a successful call to
34  * {@link CameraDevice#createExtensionSession} as part of the argument
35  * in the registered state callback {@link StateCallback#onConfigured}
36  * method. </p>
37  *
38  * <p>Note that CameraExtensionSession is currently limited to a maximum of two output
39  * surfaces for continuous repeating and multi-frame processing respectively. Some
40  * features such as capture settings will not be supported as the device-specific
41  * Extension is allowed to override all capture parameters.</p>
42  *
43  * <p>Information about support for specific device-specific extensions can be queried
44  * from {@link CameraExtensionCharacteristics}. </p>
45  */
46 public abstract class CameraExtensionSession implements AutoCloseable {
47      /** @hide */
CameraExtensionSession()48     public CameraExtensionSession () {}
49 
50     /**
51      * A callback object for tracking the progress of a
52      * {@link CaptureRequest} submitted to the camera device.
53      *
54      * <p>This callback is invoked when a request triggers a capture to start,
55      * and when the device-specific Extension post processing begins. In case of an
56      * error capturing an image, the error method is triggered instead of
57      * the completion method.</p>
58      *
59      * @see #capture
60      * @see #setRepeatingRequest
61      */
62     public static abstract class ExtensionCaptureCallback {
63 
64         /**
65          * This method is called when the camera device has started
66          * capturing the initial input image of the device-specific extension
67          * post-process request.
68          *
69          * <p>This callback is invoked right as the capture of a frame begins,
70          * so it is the most appropriate time for playing a shutter sound,
71          * or triggering UI indicators of capture.</p>
72          *
73          * <p>The request that is being used for this capture is provided,
74          * along with the actual timestamp for the start of exposure.</p>
75          *
76          * <p>The default implementation of this method does nothing.</p>
77          *
78          * @param session   the session received during
79          *                  {@link StateCallback#onConfigured(CameraExtensionSession)}
80          * @param request   the request for the capture that just begun
81          * @param timestamp the timestamp at start of capture for repeating
82          *                  request or the timestamp at start of capture of the
83          *                  first frame in a multi-frame capture.
84          */
onCaptureStarted(@onNull CameraExtensionSession session, @NonNull CaptureRequest request, long timestamp)85         public void onCaptureStarted(@NonNull CameraExtensionSession session,
86                 @NonNull CaptureRequest request, long timestamp) {
87             // default empty implementation
88         }
89 
90         /**
91          * This method is called when an image (or images in case of multi-frame
92          * capture) is captured and device-specific extension
93          * processing is triggered.
94          *
95          * <p>Each request will generate at most {@code 1}
96          * {@link #onCaptureProcessStarted}.</p>
97          *
98          * <p>The default implementation of this method does nothing.</p>
99          *
100          * @param session the session received during
101          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
102          * @param request The request that was given to the CameraExtensionSession
103          *
104          * @see #capture
105          * @see #setRepeatingRequest
106          */
onCaptureProcessStarted(@onNull CameraExtensionSession session, @NonNull CaptureRequest request)107         public void onCaptureProcessStarted(@NonNull CameraExtensionSession session,
108                 @NonNull CaptureRequest request) {
109             // default empty implementation
110         }
111 
112         /**
113          * This method is called instead of
114          * {@link #onCaptureProcessStarted} when the camera device failed
115          * to produce the required input for the device-specific extension. The
116          * cause could be a failed camera capture request, a failed
117          * capture result or dropped camera frame.
118          *
119          * <p>Other requests are unaffected, and some or all image buffers
120          * from the capture may have been pushed to their respective output
121          * streams.</p>
122          *
123          * <p>The default implementation of this method does nothing.</p>
124          *
125          * @param session the session received during
126          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
127          * @param request The request that was given to the CameraDevice
128          *
129          * @see #capture
130          * @see #setRepeatingRequest
131          */
onCaptureFailed(@onNull CameraExtensionSession session, @NonNull CaptureRequest request)132         public void onCaptureFailed(@NonNull CameraExtensionSession session,
133                 @NonNull CaptureRequest request) {
134             // default empty implementation
135         }
136 
137         /**
138          * This method is called instead of
139          * {@link #onCaptureProcessStarted} when the camera device failed
140          * to produce the required input for the device-specific extension. The
141          * cause could be a failed camera capture request, a failed
142          * capture result or dropped camera frame. More information about
143          * the reason is included in the 'failure' argument.
144          *
145          * <p>Other requests are unaffected, and some or all image buffers
146          * from the capture may have been pushed to their respective output
147          * streams.</p>
148          *
149          * <p>The default implementation of this method does nothing.</p>
150          *
151          * @param session the session received during
152          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
153          * @param request The request that was given to the CameraDevice
154          * @param failure The capture failure reason
155          *
156          * @see #capture
157          * @see #setRepeatingRequest
158          */
onCaptureFailed(@onNull CameraExtensionSession session, @NonNull CaptureRequest request, @CaptureFailure.FailureReason int failure)159         public void onCaptureFailed(@NonNull CameraExtensionSession session,
160                 @NonNull CaptureRequest request, @CaptureFailure.FailureReason int failure) {
161             // default empty implementation
162         }
163 
164         /**
165          * This method is called independently of the others in
166          * ExtensionCaptureCallback, when a capture sequence finishes.
167          *
168          * <p>In total, there will be at least one
169          * {@link #onCaptureProcessStarted}/{@link #onCaptureFailed}
170          * invocation before this callback is triggered. If the capture
171          * sequence is aborted before any requests have begun processing,
172          * {@link #onCaptureSequenceAborted} is invoked instead.</p>
173          *
174          * <p>The default implementation does nothing.</p>
175          *
176          * @param session    the session received during
177          *                   {@link StateCallback#onConfigured(CameraExtensionSession)}
178          * @param sequenceId A sequence ID returned by the {@link #capture}
179          *                   family of functions.
180          * @see #onCaptureSequenceAborted
181          */
onCaptureSequenceCompleted(@onNull CameraExtensionSession session, int sequenceId)182         public void onCaptureSequenceCompleted(@NonNull CameraExtensionSession session,
183                 int sequenceId) {
184             // default empty implementation
185         }
186 
187         /**
188          * This method is called when a capture sequence aborts.
189          *
190          * <p>Due to the asynchronous nature of the camera device, not all
191          * submitted captures are immediately processed. It is possible to
192          * clear out the pending requests by a variety of operations such
193          * as {@link CameraExtensionSession#stopRepeating}. When such an event
194          * happens, {@link #onCaptureProcessStarted} will not be called.</p>
195          *
196          * <p>The default implementation does nothing.</p>
197          *
198          * @param session    the session received during
199          *                   {@link StateCallback#onConfigured(CameraExtensionSession)}
200          * @param sequenceId A sequence ID returned by the {@link #capture}
201          *                   family of functions.
202          * @see #onCaptureProcessStarted
203          */
onCaptureSequenceAborted(@onNull CameraExtensionSession session, int sequenceId)204         public void onCaptureSequenceAborted(@NonNull CameraExtensionSession session,
205                 int sequenceId) {
206             // default empty implementation
207         }
208 
209         /**
210          * This method is called when an image capture has fully completed and all the
211          * result metadata is available.
212          *
213          * <p>This callback will only be called in case
214          * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys} returns a valid
215          * non-empty list.</p>
216          *
217          * <p>The default implementation of this method does nothing.</p>
218          *
219          * @param session The session received during
220          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
221          * @param request The request that was given to the CameraDevice
222          * @param result The total output metadata from the capture, which only includes the
223          * capture result keys advertised as supported in
224          * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys}.
225          *
226          * @see #capture
227          * @see #setRepeatingRequest
228          * @see CameraExtensionCharacteristics#getAvailableCaptureResultKeys
229          */
onCaptureResultAvailable(@onNull CameraExtensionSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result)230         public void onCaptureResultAvailable(@NonNull CameraExtensionSession session,
231                 @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
232             // default empty implementation
233         }
234 
235         /**
236          * This method is called when image capture processing is ongoing between
237          * {@link #onCaptureProcessStarted} and the processed still capture frame returning
238          * to the client surface.
239          *
240          * <p>The value included in the arguments provides clients with an estimate
241          * of the post-processing progress which could take significantly more time
242          * relative to the rest of the {@link #capture} sequence.</p>
243          *
244          * <p>The callback will be triggered only by extensions that return {@code true}
245          * from calls
246          * {@link CameraExtensionCharacteristics#isCaptureProcessProgressAvailable}.</p>
247          *
248          * <p>If support for this callback is present, then clients will be notified at least once
249          * with progress value 100.</p>
250          *
251          * <p>The callback will be triggered only for still capture requests {@link #capture} and
252          * is not supported for repeating requests {@link #setRepeatingRequest}.</p>
253          *
254          * <p>The default implementation of this method does nothing.</p>
255          *
256          * @param session The session received during
257          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
258          * @param request The request that was given to the CameraDevice
259          * @param progress Value between 0 and 100 (inclusive) indicating the current
260          *                post-processing progress
261          *
262          * @see CameraExtensionCharacteristics#isCaptureProcessProgressAvailable
263          *
264          */
onCaptureProcessProgressed(@onNull CameraExtensionSession session, @NonNull CaptureRequest request, @IntRange(from = 0, to = 100) int progress)265         public void onCaptureProcessProgressed(@NonNull CameraExtensionSession session,
266                 @NonNull CaptureRequest request, @IntRange(from = 0, to = 100) int progress) {
267             // default empty implementation
268         }
269     }
270 
271     /**
272      * A callback object for receiving updates about the state of a camera extension session.
273      *
274      */
275     public static abstract class StateCallback {
276 
277         /**
278          * This method is called when the camera device has finished configuring itself, and the
279          * session can start processing capture requests.
280          *
281          * <p>If the camera device configuration fails, then {@link #onConfigureFailed} will
282          * be invoked instead of this callback.</p>
283          *
284          * @param session A valid extension session
285          */
onConfigured(@onNull CameraExtensionSession session)286         public abstract void onConfigured(@NonNull CameraExtensionSession session);
287 
288         /**
289          * This method is called if the session cannot be configured as requested.
290          *
291          * <p>This can happen if the set of requested outputs contains unsupported sizes,
292          * too many outputs are requested at once or when trying to initialize multiple
293          * concurrent extension sessions from two (or more) separate camera devices
294          * or the camera device encounters an unrecoverable error during configuration.</p>
295          *
296          * <p>The session is considered to be closed, and all methods called on it after this
297          * callback is invoked will throw an IllegalStateException.</p>
298          *
299          * @param session the session instance that failed to configure
300          */
onConfigureFailed(@onNull CameraExtensionSession session)301         public abstract void onConfigureFailed(@NonNull CameraExtensionSession session);
302 
303         /**
304          * This method is called when the session is closed.
305          *
306          * <p>A session is closed when a new session is created by the parent camera device,
307          * or when the parent camera device is closed (either by the user closing the device,
308          * or due to a camera device disconnection or fatal error).</p>
309          *
310          * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and
311          * any repeating requests are stopped (as if {@link #stopRepeating()} was called).
312          * However, any in-progress capture requests submitted to the session will be completed
313          * as normal.</p>
314          *
315          * @param session the session received during
316          *                {@link StateCallback#onConfigured(CameraExtensionSession)}
317          */
onClosed(@onNull CameraExtensionSession session)318         public void onClosed(@NonNull CameraExtensionSession session) {
319             // default empty implementation
320         }
321     }
322 
323     /**
324      * Get the camera device that this session is created for.
325      */
326     @NonNull
getDevice()327     public android.hardware.camera2.CameraDevice getDevice() {
328         throw new UnsupportedOperationException("Subclasses must override this method");
329     }
330 
331     /**
332      * Submit a request for device-specific processing using input
333      * from the camera device, to produce a single high-quality output result.
334      *
335      * <p>Note that single capture requests currently do not support
336      * client parameters except for controls advertised in
337      * {@link CameraExtensionCharacteristics#getAvailableCaptureRequestKeys}.
338      * The rest of the settings included in the request will be entirely overridden by
339      * the device-specific extension. </p>
340      *
341      * <p> If {@link CameraExtensionCharacteristics#isPostviewAvailable} returns
342      * false, the {@link CaptureRequest.Builder#addTarget} will support only one
343      * ImageFormat.YUV_420_888 or ImageFormat.JPEG target surface. {@link CaptureRequest}
344      * arguments that include further targets will cause IllegalArgumentException to be thrown.
345      * If postview is available, {@link CaptureRequest.Builder#addTarget} will support up to two
346      * ImageFormat.YUV_420_888 or ImageFormat.JPEG target surfaces for the still capture and
347      * postview. IllegalArgumentException will be thrown if a postview target is added without
348      * a still capture target, if more than two target surfaces are added, or if the surface
349      * formats for postview and capture are not equivalent.
350      *
351      * <p>Starting with Android {@link android.os.Build.VERSION_CODES#TIRAMISU} single capture
352      * requests will also support the preview {@link android.graphics.ImageFormat#PRIVATE} target
353      * surface. These can typically be used for enabling AF/AE triggers. Do note, that single
354      * capture requests referencing both output surfaces remain unsupported.</p>
355      *
356      * <p>Each request will produce one new frame for one target Surface, set
357      * with the CaptureRequest builder's
358      * {@link CaptureRequest.Builder#addTarget} method.</p>
359      *
360      * <p>Multiple requests can be in progress at once. Requests are
361      * processed in first-in, first-out order.</p>
362      *
363      * <p>Requests submitted through this method have higher priority than
364      * those submitted through {@link #setRepeatingRequest}, and will be
365      * processed as soon as the current repeat processing completes.</p>
366      *
367      * @param request the settings for this capture
368      * @param executor the executor which will be used for invoking the
369      *                 listener.
370      * @param listener The callback object to notify once this request has
371      *                 been processed.
372      * @return int A unique capture sequence ID used by
373      * {@link ExtensionCaptureCallback#onCaptureSequenceCompleted}.
374      * @throws CameraAccessException    if the camera device is no longer
375      *                                  connected or has encountered a fatal error
376      * @throws IllegalStateException    if this session is no longer active,
377      *                                  either because the session was explicitly closed, a new
378      *                                  session has been created or the camera device has been
379      *                                  closed.
380      * @throws IllegalArgumentException if the request targets no Surfaces
381      *                                  or Surfaces that are not configured as outputs for this
382      *                                  session; or the request targets a set of Surfaces that
383      *                                  cannot be submitted simultaneously.
384      */
capture(@onNull CaptureRequest request, @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener)385     public int capture(@NonNull CaptureRequest request,
386             @NonNull Executor executor,
387             @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
388         throw new UnsupportedOperationException("Subclasses must override this method");
389     }
390 
391     /**
392      * Request endlessly repeating device-specific extension processing of
393      * camera images.
394      *
395      * <p>With this method, the camera device will continually capture images
396      * and process them using the device-specific extension at the maximum
397      * rate possible.</p>
398      *
399      * <p>Note that repeating capture requests currently do not support
400      * client parameters except for controls advertised in
401      * {@link CameraExtensionCharacteristics#getAvailableCaptureRequestKeys}.
402      * The rest of the settings included in the request will be entirely overridden by
403      * the device-specific extension. </p>
404      *
405      * <p>The {@link CaptureRequest.Builder#addTarget} supports only one
406      * target surface. {@link CaptureRequest} arguments that include further
407      * targets will cause IllegalArgumentException to be thrown.</p>
408      *
409      * <p>Repeating requests are a simple way for an application to maintain a
410      * preview or other continuous stream of frames.</p>
411      *
412      * <p>Repeat requests have lower priority than those submitted
413      * through {@link #capture}, so if  {@link #capture} is called when a
414      * repeating request is active, the capture request will be processed
415      * before any further repeating requests are processed.</p>
416      *
417      * <p>To stop the repeating capture, call {@link #stopRepeating}.</p>
418      *
419      * <p>Calling this method will replace any earlier repeating request.</p>
420      *
421      * @param request the request to repeat indefinitely
422      * @param executor the executor which will be used for invoking the
423      *                 listener.
424      * @param listener The callback object to notify every time the
425      *                 request finishes processing.
426      * @return int A unique capture sequence ID used by
427      * {@link ExtensionCaptureCallback#onCaptureSequenceCompleted}.
428      * @throws CameraAccessException    if the camera device is no longer
429      *                                  connected or has encountered a fatal error
430      * @throws IllegalStateException    if this session is no longer active,
431      *                                  either because the session was explicitly closed, a new
432      *                                  session has been created or the camera device has been
433      *                                  closed.
434      * @throws IllegalArgumentException If the request references no
435      *                                  Surfaces or references Surfaces that are not currently
436      *                                  configured as outputs.
437      * @see #capture
438      */
setRepeatingRequest(@onNull CaptureRequest request, @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener)439     public int setRepeatingRequest(@NonNull CaptureRequest request,
440             @NonNull Executor executor,
441             @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
442         throw new UnsupportedOperationException("Subclasses must override this method");
443     }
444 
445     /**
446      * Cancel any ongoing repeating capture set by
447      * {@link #setRepeatingRequest setRepeatingRequest}. Has no effect on
448      * requests submitted through {@link #capture capture}.
449      *
450      * <p>Any currently in-flight captures will still complete.</p>
451      *
452      * @throws CameraAccessException if the camera device is no longer
453      *                               connected or has  encountered a fatal error
454      * @throws IllegalStateException if this session is no longer active,
455      *                               either because the session was explicitly closed, a new
456      *                               session has been created or the camera device has been closed.
457      * @see #setRepeatingRequest
458      */
stopRepeating()459     public void stopRepeating() throws CameraAccessException {
460         throw new UnsupportedOperationException("Subclasses must override this method");
461     }
462 
463     /**
464      * Realtime calculated still {@link #capture} latency.
465      *
466      * @see #getRealtimeStillCaptureLatency()
467      */
468     public final static class StillCaptureLatency {
469         private final long mCaptureLatency, mProcessingLatency;
470 
StillCaptureLatency(long captureLatency, long processingLatency)471         public StillCaptureLatency(long captureLatency, long processingLatency) {
472             mCaptureLatency = captureLatency;
473             mProcessingLatency = processingLatency;
474         }
475         /**
476          * Return the capture latency from
477          * {@link ExtensionCaptureCallback#onCaptureStarted} until
478          * {@link ExtensionCaptureCallback#onCaptureProcessStarted}.
479          *
480          * @return The realtime capture latency in milliseconds.
481          */
getCaptureLatency()482         public long getCaptureLatency() {
483             return mCaptureLatency;
484         }
485 
486         /**
487          * Return the estimated post-processing latency from
488          * {@link ExtensionCaptureCallback#onCaptureProcessStarted} until the processed frame
489          * returns to the client.
490          *
491          * @return returns post-processing latency in milliseconds
492          */
getProcessingLatency()493         public long getProcessingLatency() {
494             return mProcessingLatency;
495         }
496 
497         @Override
equals(Object o)498         public boolean equals(Object o) {
499             if (this == o) return true;
500             if (o == null || getClass() != o.getClass()) return false;
501 
502             StillCaptureLatency latency = (StillCaptureLatency) o;
503 
504             if (mCaptureLatency != latency.mCaptureLatency) return false;
505             if (mProcessingLatency != latency.mProcessingLatency) return false;
506 
507             return true;
508         }
509 
510         @Override
hashCode()511         public int hashCode() {
512             return HashCodeHelpers.hashCode(mCaptureLatency, mProcessingLatency);
513         }
514 
515         @Override
toString()516         public String toString() {
517             return "StillCaptureLatency(processingLatency:" + mProcessingLatency +
518                     ", captureLatency: " + mCaptureLatency + ")";
519         }
520     }
521 
522     /**
523      * Return the realtime still {@link #capture} latency.
524      *
525      * <p>The estimations will take into account the current environment conditions, the camera
526      * state and will include the time spent processing the multi-frame capture request along with
527      * any additional time for encoding of the processed buffer if necessary.</p>
528      *
529      * @return The realtime still capture latency,
530      * or {@code null} if the estimation is not supported.
531      */
532     @Nullable
getRealtimeStillCaptureLatency()533     public StillCaptureLatency getRealtimeStillCaptureLatency() throws CameraAccessException {
534         throw new UnsupportedOperationException("Subclasses must override this method");
535     }
536 
537     /**
538      * Close this capture session asynchronously.
539      *
540      * <p>Closing a session frees up the target output Surfaces of the session
541      * for reuse with either a new session, or to other APIs that can draw
542      * to Surfaces.</p>
543      *
544      * <p>Note that creating a new capture session with
545      * {@link android.hardware.camera2.CameraDevice#createCaptureSession} or
546      * {@link android.hardware.camera2.CameraDevice#createExtensionSession}
547      * will close any existing capture session automatically, and call the
548      * older session listener's {@link StateCallback#onClosed} callback.
549      * Using
550      * {@link android.hardware.camera2.CameraDevice#createCaptureSession} or
551      * {@link android.hardware.camera2.CameraDevice#createExtensionSession}
552      * directly without closing is the recommended approach for quickly
553      * switching to a new session, since unchanged target outputs can be
554      * reused more efficiently.</p>
555      *
556      * <p>Once a session is closed, all methods on it will throw an
557      * IllegalStateException, and any repeating requests are
558      * stopped (as if {@link #stopRepeating()} was called).</p>
559      *
560      * <p>Closing a session is idempotent; closing more than once has no
561      * effect.</p>
562      */
close()563     public void close() throws CameraAccessException {
564         throw new UnsupportedOperationException("Subclasses must override this method");
565     }
566 }
567