Java tutorial
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.camera2.params.OutputConfiguration; import android.os.Handler; import android.view.Surface; import java.util.concurrent.Executor; import java.util.List; /** * A configured capture session for a {@link CameraDevice}, used for capturing images from the * camera or reprocessing images captured from the camera in the same session previously. * * <p>A CameraCaptureSession is created by providing a set of target output surfaces to * {@link CameraDevice#createCaptureSession createCaptureSession}, or by providing an * {@link android.hardware.camera2.params.InputConfiguration} and a set of target output surfaces to * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} for a * reprocessable capture session. Once created, the session is active until a new session is * created by the camera device, or the camera device is closed.</p> * * <p>All capture sessions can be used for capturing images from the camera but only reprocessable * capture sessions can reprocess images captured from the camera in the same session previously. * </p> * * <p>Creating a session is an expensive operation and can take several hundred milliseconds, since * it requires configuring the camera device's internal pipelines and allocating memory buffers for * sending images to the desired targets. Therefore the setup is done asynchronously, and * {@link CameraDevice#createCaptureSession createCaptureSession} and * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} will * send the ready-to-use CameraCaptureSession to the provided listener's * {@link CameraCaptureSession.StateCallback#onConfigured onConfigured} callback. If configuration * cannot be completed, then the * {@link CameraCaptureSession.StateCallback#onConfigureFailed onConfigureFailed} is called, and the * session will not become active.</p> *<!-- * <p>Any capture requests (repeating or non-repeating) submitted before the session is ready will * be queued up and will begin capture once the session becomes ready. In case the session cannot be * configured and {@link StateCallback#onConfigureFailed onConfigureFailed} is called, all queued * capture requests are discarded.</p> *--> * <p>If a new session is created by the camera device, then the previous session is closed, and its * associated {@link StateCallback#onClosed onClosed} callback will be invoked. All * of the session methods will throw an IllegalStateException if called once the session is * closed.</p> * * <p>A closed session clears any repeating requests (as if {@link #stopRepeating} had been called), * but will still complete all of its in-progress capture requests as normal, before a newly * created session takes over and reconfigures the camera device.</p> */ public abstract class CameraCaptureSession implements AutoCloseable { /** * Used to identify invalid session ID. * @hide */ public static final int SESSION_ID_NONE = -1; /** * Get the camera device that this session is created for. */ @NonNull public abstract CameraDevice getDevice(); /** * <p>Pre-allocate all buffers for an output Surface.</p> * * <p>Normally, the image buffers for a given output Surface are allocated on-demand, * to minimize startup latency and memory overhead.</p> * * <p>However, in some cases, it may be desirable for the buffers to be allocated before * any requests targeting the Surface are actually submitted to the device. Large buffers * may take some time to allocate, which can result in delays in submitting requests until * sufficient buffers are allocated to reach steady-state behavior. Such delays can cause * bursts to take longer than desired, or cause skips or stutters in preview output.</p> * * <p>The prepare() method can be used to perform this preallocation. It may only be called for * a given output Surface before that Surface is used as a target for a request. The number of * buffers allocated is the sum of the count needed by the consumer providing the output * Surface, and the maximum number needed by the camera device to fill its pipeline. Since this * may be a larger number than what is actually required for steady-state operation, using * prepare may result in higher memory consumption than the normal on-demand behavior results * in. Prepare() will also delay the time to first output to a given Surface, in exchange for * smoother frame rate once the allocation is complete.</p> * * <p>For example, an application that creates an * {@link android.media.ImageReader#newInstance ImageReader} with a maxImages argument of 10, * but only uses 3 simultaneous Images at once would normally only cause those 3 images to be * allocated (plus what is needed by the camera device for smooth operation). But using * prepare() on the ImageReader Surface will result in all 10 Images being allocated. So * applications using this method should take care to request only the number of buffers * actually necessary for their application.</p> * * <p>If the same output Surface is used in consecutive sessions (without closing the first * session explicitly), then its already-allocated buffers are carried over, and if it was * used as a target of a capture request in the first session, prepare cannot be called on it * in the second session.</p> * * <p>Once allocation is complete, {@link StateCallback#onSurfacePrepared} will be invoked with * the Surface provided to this method. Between the prepare call and the onSurfacePrepared call, * the Surface provided to prepare must not be used as a target of a CaptureRequest submitted * to this session.</p> * * <p>Note that if 2 surfaces share the same stream via {@link * OutputConfiguration#enableSurfaceSharing} and {@link OutputConfiguration#addSurface}, * prepare() only needs to be called on one surface, and {link * StateCallback#onSurfacePrepared} will be triggered for both surfaces.</p> * * <p>{@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} * devices cannot pre-allocate output buffers; for those devices, * {@link StateCallback#onSurfacePrepared} will be immediately called, and no preallocation is * done.</p> * * @param surface the output Surface for which buffers should be pre-allocated. Must be one of * the output Surfaces used to create this session. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, or has * already been used as a target of a CaptureRequest in this * session or immediately prior sessions. * * @see StateCallback#onSurfacePrepared */ public abstract void prepare(@NonNull Surface surface) throws CameraAccessException; /** * <p>Pre-allocate at most maxCount buffers for an output Surface.</p> * * <p>Like the {@link #prepare(Surface)} method, this method can be used to allocate output * buffers for a given Surface. However, while the {@link #prepare(Surface)} method allocates * the maximum possible buffer count, this method allocates at most maxCount buffers.</p> * * <p>If maxCount is greater than the possible maximum count (which is the sum of the buffer * count requested by the creator of the Surface and the count requested by the camera device), * only the possible maximum count is allocated, in which case the function acts exactly like * {@link #prepare(Surface)}.</p> * * <p>The restrictions on when this method can be called are the same as for * {@link #prepare(Surface)}.</p> * * <p>Repeated calls to this method are allowed, and a mix of {@link #prepare(Surface)} and * this method is also allowed. Note that after the first call to {@link #prepare(Surface)}, * subsequent calls to either prepare method are effectively no-ops. In addition, this method * is not additive in terms of buffer count. This means calling it twice with maxCount = 2 * will only allocate 2 buffers, not 4 (assuming the possible maximum is at least 2); to * allocate two buffers on the first call and two on the second, the application needs to call * prepare with prepare(surface, 2) and prepare(surface, 4).</p> * * @param maxCount the buffer count to try to allocate. If this is greater than the possible * maximum for this output, the possible maximum is allocated instead. If * maxCount buffers are already allocated, then prepare will do nothing. * @param surface the output Surface for which buffers should be pre-allocated. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error. * @throws IllegalStateException if this session is no longer active, either because the * session was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, * or has already been used as a target of a CaptureRequest in * this session or immediately prior sessions without an * intervening tearDown call. * * @hide */ public abstract void prepare(int maxCount, @NonNull Surface surface) throws CameraAccessException; /** * <p>Free all buffers allocated for an output Surface.</p> * * <p>Normally, once allocated, the image buffers for a given output Surface remain allocated * for the lifetime of the capture session, to minimize latency of captures and to reduce * memory allocation overhead.</p> * * <p>However, in some cases, it may be desirable for allocated buffers to be freed to reduce * the application's memory consumption, if the particular output Surface will not be used by * the application for some time.</p> * * <p>The tearDown() method can be used to perform this operation. After the call finishes, all * unfilled image buffers will have been freed. Any future use of the target Surface may require * allocation of additional buffers, as if the session had just been created. Buffers being * held by the application (either explicitly as Image objects from ImageReader, or implicitly * as the current texture in a SurfaceTexture or the current contents of a RS Allocation, will * remain valid and allocated even when tearDown is invoked.</p> * * <p>A Surface that has had tearDown() called on it is eligible to have prepare() invoked on it * again even if it was used as a request target before the tearDown() call, as long as it * doesn't get used as a target of a request between the tearDown() and prepare() calls.</p> * * @param surface the output Surface for which buffers should be freed. Must be one of the * the output Surfaces used to create this session. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error. * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, or has * already been used as a target of a CaptureRequest in this * session or immediately prior sessions. * * @hide */ public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException; /** * <p>Finalize the output configurations that now have their deferred and/or extra Surfaces * included.</p> * * <p>For camera use cases where a preview and other output configurations need to be * configured, it can take some time for the preview Surface to be ready. For example, if the * preview Surface is obtained from {@link android.view.SurfaceView}, the SurfaceView will only * be ready after the UI layout is done, potentially delaying camera startup.</p> * * <p>To speed up camera startup time, the application can configure the * {@link CameraCaptureSession} with the eventual preview size (via * {@link OutputConfiguration#OutputConfiguration(Size,Class) a deferred OutputConfiguration}), * and defer the preview output configuration until the Surface is ready. After the * {@link CameraCaptureSession} is created successfully with this deferred output and other * normal outputs, the application can start submitting requests as long as they do not include * deferred output Surfaces. Once a deferred Surface is ready, the application can add the * Surface to the deferred output configuration with the * {@link OutputConfiguration#addSurface} method, and then update the deferred output * configuration via this method, before it can submit capture requests with this output * target.</p> * * <p>This function can also be called in case where multiple surfaces share the same * OutputConfiguration, and one of the surfaces becomes available after the {@link * CameraCaptureSession} is created. In that case, the application must first create the * OutputConfiguration with the available Surface, then enable further surface sharing via * {@link OutputConfiguration#enableSurfaceSharing}, before creating the CameraCaptureSession. * After the CameraCaptureSession is created, and once the extra Surface becomes available, the * application must then call {@link OutputConfiguration#addSurface} before finalizing the * configuration with this method.</p> * * <p>If the provided OutputConfigurations are unchanged from session creation, this function * call has no effect. This function must only be called once for a particular output * configuration. </p> * * <p>The output Surfaces included by this list of * {@link OutputConfiguration OutputConfigurations} can be used as {@link CaptureRequest} * targets as soon as this call returns.</p> * * <p>This method is not supported by * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}-level devices.</p> * * @param outputConfigs a list of {@link OutputConfiguration OutputConfigurations} that * have had {@link OutputConfiguration#addSurface addSurface} invoked with a valid * output Surface after {@link CameraDevice#createCaptureSessionByOutputConfigurations}. * @throws CameraAccessException if the camera device is no longer connected or has encountered * a fatal error. * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created, or the camera device has * been closed. * @throws IllegalArgumentException for invalid output configurations, including ones where the * source of the Surface is no longer valid or the Surface is from a unsupported * source. Or if one of the output configuration was already finished with an * included surface in a prior call. */ public abstract void finalizeOutputConfigurations(List<OutputConfiguration> outputConfigs) throws CameraAccessException; /** * <p>Submit a request for an image to be captured by the camera device.</p> * * <p>The request defines all the parameters for capturing the single image, * including sensor, lens, flash, and post-processing settings.</p> * * <p>Each request will produce one {@link CaptureResult} and produce new frames for one or more * target Surfaces, set with the CaptureRequest builder's * {@link CaptureRequest.Builder#addTarget} method. The target surfaces (set with * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when this * capture session was created.</p> * * <p>Multiple regular and reprocess requests can be in progress at once. If there are only * regular requests or reprocess requests in progress, they are processed in first-in, * first-out order. If there are both regular and reprocess requests in progress, regular * requests are processed in first-in, first-out order and reprocess requests are processed in * first-in, first-out order, respectively. However, the processing order of a regular request * and a reprocess request in progress is not specified. In other words, a regular request * will always be processed before regular requets that are submitted later. A reprocess request * will always be processed before reprocess requests that are submitted later. However, a * regular request may not be processed before reprocess requests that are submitted later.<p> * * <p>Requests submitted through this method have higher priority than * those submitted through {@link #setRepeatingRequest} or * {@link #setRepeatingBurst}, and will be processed as soon as the current * repeat/repeatBurst processing completes.</p> * * <p>All capture sessions can be used for capturing images from the camera but only capture * sessions created by * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} * can submit reprocess capture requests. Submitting a reprocess request to a regular capture * session will result in an {@link IllegalArgumentException}.</p> * * @param request the settings for this capture * @param listener The callback object to notify once this request has been * processed. If null, no metadata will be produced for this capture, * although image data will still be produced. * @param handler the handler on which the listener should be invoked, or * {@code null} to use the current thread's {@link android.os.Looper * looper}. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not * configured as outputs for this session; or the request * targets a set of Surfaces that cannot be submitted * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a * non-reprocessable capture session; or the reprocess capture * request was created with a {@link TotalCaptureResult} from * a different session; or the capture targets a Surface in * the middle of being {@link #prepare prepared}; or the * handler is null, the listener is not null, and the calling * thread has no looper. * * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures * @see CameraDevice#createReprocessableCaptureSession */ public abstract int capture(@NonNull CaptureRequest request, @Nullable CaptureCallback listener, @Nullable Handler handler) throws CameraAccessException; /** * <p>Submit a request for an image to be captured by the camera device.</p> * * <p>The behavior of this method matches that of * {@link #capture(CaptureRequest, CaptureCallback, Handler)}, * except that it uses {@link java.util.concurrent.Executor} as an argument * instead of {@link android.os.Handler}.</p> * * @param request the settings for this capture * @param executor the executor which will be used for invoking the listener. * @param listener The callback object to notify once this request has been * processed. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not * configured as outputs for this session; or the request * targets a set of Surfaces that cannot be submitted * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a * non-reprocessable capture session; or the reprocess capture * request was created with a {@link TotalCaptureResult} from * a different session; or the capture targets a Surface in * the middle of being {@link #prepare prepared}; or the * executor is null, or the listener is not null. * * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures * @see CameraDevice#createReprocessableCaptureSession */ public int captureSingleRequest(@NonNull CaptureRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) throws CameraAccessException { throw new UnsupportedOperationException("Subclasses must override this method"); } /** * Submit a list of requests to be captured in sequence as a burst. The * burst will be captured in the minimum amount of time possible, and will * not be interleaved with requests submitted by other capture or repeat * calls. * * <p>Regular and reprocess requests can be mixed together in a single burst. Regular requests * will be captured in order and reprocess requests will be processed in order, respectively. * However, the processing order between a regular request and a reprocess request is not * specified. Each capture produces one {@link CaptureResult} and image buffers for one or more * target {@link android.view.Surface surfaces}. The target surfaces (set with * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when * this capture session was created.</p> * * <p>The main difference between this method and simply calling * {@link #capture} repeatedly is that this method guarantees that no * other requests will be interspersed with the burst.</p> * * <p>All capture sessions can be used for capturing images from the camera but only capture * sessions created by * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} * can submit reprocess capture requests. Submitting a reprocess request to a regular * capture session will result in an {@link IllegalArgumentException}.</p> * * @param requests the list of settings for this burst capture * @param listener The callback object to notify each time one of the * requests in the burst has been processed. If null, no metadata will be * produced for any requests in this burst, although image data will still * be produced. * @param handler the handler on which the listener should be invoked, or * {@code null} to use the current thread's {@link android.os.Looper * looper}. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target * Surfaces not currently configured as outputs; or one of the * requests targets a set of Surfaces that cannot be submitted * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a * non-reprocessable capture session; or one of the reprocess * capture requests was created with a * {@link TotalCaptureResult} from a different session; or one * of the captures targets a Surface in the middle of being * {@link #prepare prepared}; or if the handler is null, the * listener is not null, and the calling thread has no looper. * * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures */ public abstract int captureBurst(@NonNull List<CaptureRequest> requests, @Nullable CaptureCallback listener, @Nullable Handler handler) throws CameraAccessException; /** * Submit a list of requests to be captured in sequence as a burst. The * burst will be captured in the minimum amount of time possible, and will * not be interleaved with requests submitted by other capture or repeat * calls. * * <p>The behavior of this method matches that of * {@link #captureBurst(List, CaptureCallback, Handler)}, * except that it uses {@link java.util.concurrent.Executor} as an argument * instead of {@link android.os.Handler}.</p> * * @param requests the list of settings for this burst capture * @param executor the executor which will be used for invoking the listener. * @param listener The callback object to notify each time one of the * requests in the burst has been processed. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target * Surfaces not currently configured as outputs; or one of the * requests targets a set of Surfaces that cannot be submitted * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a * non-reprocessable capture session; or one of the reprocess * capture requests was created with a * {@link TotalCaptureResult} from a different session; or one * of the captures targets a Surface in the middle of being * {@link #prepare prepared}; or if the executor is null; or if * the listener is null. * * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures */ public int captureBurstRequests(@NonNull List<CaptureRequest> requests, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) throws CameraAccessException { throw new UnsupportedOperationException("Subclasses must override this method"); } /** * Request endlessly repeating capture of images by this capture session. * * <p>With this method, the camera device will continually capture images * using the settings in the provided {@link CaptureRequest}, at the maximum * rate possible.</p> * * <p>Repeating requests are a simple way for an application to maintain a * preview or other continuous stream of frames, without having to * continually submit identical requests through {@link #capture}.</p> * * <p>Repeat requests have lower priority than those submitted * through {@link #capture} or {@link #captureBurst}, so if * {@link #capture} is called when a repeating request is active, the * capture request will be processed before any further repeating * requests are processed.<p> * * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling * {@link #abortCaptures} will also clear the request.</p> * * <p>Calling this method will replace any earlier repeating request or * burst set up by this method or {@link #setRepeatingBurst}, although any * in-progress burst will be completed before the new repeat request will be * used.</p> * * <p>This method does not support reprocess capture requests because each reprocess * {@link CaptureRequest} must be created from the {@link TotalCaptureResult} that matches * the input image to be reprocessed. This is either the {@link TotalCaptureResult} of capture * that is sent for reprocessing, or one of the {@link TotalCaptureResult TotalCaptureResults} * of a set of captures, when data from the whole set is combined by the application into a * single reprocess input image. The request must be capturing images from the camera. If a * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p> * * @param request the request to repeat indefinitely * @param listener The callback object to notify every time the * request finishes processing. If null, no metadata will be * produced for this stream of requests, although image data will * still be produced. * @param handler the handler on which the listener should be invoked, or * {@code null} to use the current thread's {@link android.os.Looper * looper}. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the request references no Surfaces or references Surfaces * that are not currently configured as outputs; or the request * is a reprocess capture request; or the capture targets a * Surface in the middle of being {@link #prepare prepared}; or * the handler is null, the listener is not null, and the * calling thread has no looper; or no requests were passed in. * * @see #capture * @see #captureBurst * @see #setRepeatingBurst * @see #stopRepeating * @see #abortCaptures */ public abstract int setRepeatingRequest(@NonNull CaptureRequest request, @Nullable CaptureCallback listener, @Nullable Handler handler) throws CameraAccessException; /** * Request endlessly repeating capture of images by this capture session. * * <p>The behavior of this method matches that of * {@link #setRepeatingRequest(CaptureRequest, CaptureCallback, Handler)}, * except that it uses {@link java.util.concurrent.Executor} as an argument * instead of {@link android.os.Handler}.</p> * * @param request the request to repeat indefinitely * @param executor the executor which will be used for invoking the listener. * @param listener The callback object to notify every time the * request finishes processing. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the request references no Surfaces or references Surfaces * that are not currently configured as outputs; or the request * is a reprocess capture request; or the capture targets a * Surface in the middle of being {@link #prepare prepared}; or * the executor is null; or the listener is null. * * @see #capture * @see #captureBurst * @see #setRepeatingBurst * @see #stopRepeating * @see #abortCaptures */ public int setSingleRepeatingRequest(@NonNull CaptureRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) throws CameraAccessException { throw new UnsupportedOperationException("Subclasses must override this method"); } /** * <p>Request endlessly repeating capture of a sequence of images by this * capture session.</p> * * <p>With this method, the camera device will continually capture images, * cycling through the settings in the provided list of * {@link CaptureRequest CaptureRequests}, at the maximum rate possible.</p> * * <p>If a request is submitted through {@link #capture} or * {@link #captureBurst}, the current repetition of the request list will be * completed before the higher-priority request is handled. This guarantees * that the application always receives a complete repeat burst captured in * minimal time, instead of bursts interleaved with higher-priority * captures, or incomplete captures.</p> * * <p>Repeating burst requests are a simple way for an application to * maintain a preview or other continuous stream of frames where each * request is different in a predicatable way, without having to continually * submit requests through {@link #captureBurst}.</p> * * <p>To stop the repeating capture, call {@link #stopRepeating}. Any * ongoing burst will still be completed, however. Calling * {@link #abortCaptures} will also clear the request.</p> * * <p>Calling this method will replace a previously-set repeating request or * burst set up by this method or {@link #setRepeatingRequest}, although any * in-progress burst will be completed before the new repeat burst will be * used.</p> * * <p>This method does not support reprocess capture requests because each reprocess * {@link CaptureRequest} must be created from the {@link TotalCaptureResult} that matches * the input image to be reprocessed. This is either the {@link TotalCaptureResult} of capture * that is sent for reprocessing, or one of the {@link TotalCaptureResult TotalCaptureResults} * of a set of captures, when data from the whole set is combined by the application into a * single reprocess input image. The request must be capturing images from the camera. If a * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p> * * @param requests the list of requests to cycle through indefinitely * @param listener The callback object to notify each time one of the * requests in the repeating bursts has finished processing. If null, no * metadata will be produced for this stream of requests, although image * data will still be produced. * @param handler the handler on which the listener should be invoked, or * {@code null} to use the current thread's {@link android.os.Looper * looper}. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the requests reference no Surfaces or reference Surfaces * not currently configured as outputs; or one of the requests * is a reprocess capture request; or one of the captures * targets a Surface in the middle of being * {@link #prepare prepared}; or the handler is null, the * listener is not null, and the calling thread has no looper; * or no requests were passed in. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #stopRepeating * @see #abortCaptures */ public abstract int setRepeatingBurst(@NonNull List<CaptureRequest> requests, @Nullable CaptureCallback listener, @Nullable Handler handler) throws CameraAccessException; /** * <p>Request endlessly repeating capture of a sequence of images by this * capture session.</p> * * <p>The behavior of this method matches that of * {@link #setRepeatingBurst(List, CaptureCallback, Handler)}, * except that it uses {@link java.util.concurrent.Executor} as an argument * instead of {@link android.os.Handler}.</p> * * @param requests the list of requests to cycle through indefinitely * @param executor the executor which will be used for invoking the listener. * @param listener The callback object to notify each time one of the * requests in the repeating bursts has finished processing. * * @return int A unique capture sequence ID used by * {@link CaptureCallback#onCaptureSequenceCompleted}. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * @throws IllegalArgumentException If the requests reference no Surfaces or reference Surfaces * not currently configured as outputs; or one of the requests * is a reprocess capture request; or one of the captures * targets a Surface in the middle of being * {@link #prepare prepared}; or the executor is null; or the * listener is null. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #stopRepeating * @see #abortCaptures */ public int setRepeatingBurstRequests(@NonNull List<CaptureRequest> requests, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) throws CameraAccessException { throw new UnsupportedOperationException("Subclasses must override this method"); } /** * <p>Cancel any ongoing repeating capture set by either * {@link #setRepeatingRequest setRepeatingRequest} or * {@link #setRepeatingBurst}. Has no effect on requests submitted through * {@link #capture capture} or {@link #captureBurst captureBurst}.</p> * * <p>Any currently in-flight captures will still complete, as will any burst that is * mid-capture. To ensure that the device has finished processing all of its capture requests * and is in ready state, wait for the {@link StateCallback#onReady} callback after * calling this method.</p> * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * * @see #setRepeatingRequest * @see #setRepeatingBurst * @see StateCallback#onIdle */ public abstract void stopRepeating() throws CameraAccessException; /** * Discard all captures currently pending and in-progress as fast as possible. * * <p>The camera device will discard all of its current work as fast as possible. Some in-flight * captures may complete successfully and call {@link CaptureCallback#onCaptureCompleted}, while * others will trigger their {@link CaptureCallback#onCaptureFailed} callbacks. If a repeating * request or a repeating burst is set, it will be cleared.</p> * * <p>This method is the fastest way to switch the camera device to a new session with * {@link CameraDevice#createCaptureSession} or * {@link CameraDevice#createReprocessableCaptureSession}, at the cost of discarding in-progress * work. It must be called before the new session is created. Once all pending requests are * either completed or thrown away, the {@link StateCallback#onReady} callback will be called, * if the session has not been closed. Otherwise, the {@link StateCallback#onClosed} * callback will be fired when a new session is created by the camera device.</p> * * <p>Cancelling will introduce at least a brief pause in the stream of data from the camera * device, since once the camera device is emptied, the first new request has to make it through * the entire camera pipeline before new output buffers are produced.</p> * * <p>This means that using {@code abortCaptures()} to simply remove pending requests is not * recommended; it's best used for quickly switching output configurations, or for cancelling * long in-progress requests (such as a multi-second capture).</p> * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. * * @see #setRepeatingRequest * @see #setRepeatingBurst * @see CameraDevice#createCaptureSession * @see CameraDevice#createReprocessableCaptureSession */ public abstract void abortCaptures() throws CameraAccessException; /** * Return if the application can submit reprocess capture requests with this camera capture * session. * * @return {@code true} if the application can submit reprocess capture requests with this * camera capture session. {@code false} otherwise. * * @see CameraDevice#createReprocessableCaptureSession */ public abstract boolean isReprocessable(); /** * Get the input Surface associated with a reprocessable capture session. * * <p>Each reprocessable capture session has an input {@link Surface} where the reprocess * capture requests get the input images from, rather than the camera device. The application * can create a {@link android.media.ImageWriter ImageWriter} with this input {@link Surface} * and use it to provide input images for reprocess capture requests. When the reprocessable * capture session is closed, the input {@link Surface} is abandoned and becomes invalid.</p> * * @return The {@link Surface} where reprocessing capture requests get the input images from. If * this is not a reprocess capture session, {@code null} will be returned. * * @see CameraDevice#createReprocessableCaptureSession * @see android.media.ImageWriter * @see android.media.ImageReader */ @Nullable public abstract Surface getInputSurface(); /** * Update {@link OutputConfiguration} after configuration finalization see * {@link #finalizeOutputConfigurations}. * * <p>Any {@link OutputConfiguration} that has been modified via calls to * {@link OutputConfiguration#addSurface} or {@link OutputConfiguration#removeSurface} must be * updated. After the update call returns without throwing exceptions any newly added surfaces * can be referenced in subsequent capture requests.</p> * * <p>Surfaces that get removed must not be part of any active repeating or single/burst * request or have any pending results. Consider updating any repeating requests first via * {@link #setRepeatingRequest} or {@link #setRepeatingBurst} and then wait for the last frame * number when the sequence completes {@link CaptureCallback#onCaptureSequenceCompleted} * before calling updateOutputConfiguration to remove a previously active Surface.</p> * * <p>Surfaces that get added must not be part of any other registered * {@link OutputConfiguration}.</p> * * @param config Modified output configuration. * * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error. * @throws IllegalArgumentException if an attempt was made to add a {@link Surface} already * in use by another buffer-producing API, such as MediaCodec or * a different camera device or {@link OutputConfiguration}; or * new surfaces are not compatible (see * {@link OutputConfiguration#enableSurfaceSharing}); or a * {@link Surface} that was removed from the modified * {@link OutputConfiguration} still has pending requests. * @throws IllegalStateException if this session is no longer active, either because the session * was explicitly closed, a new session has been created * or the camera device has been closed. */ public void updateOutputConfiguration(OutputConfiguration config) throws CameraAccessException { throw new UnsupportedOperationException("Subclasses must override this method"); } /** * Close this capture session asynchronously. * * <p>Closing a session frees up the target output Surfaces of the session for reuse with either * a new session, or to other APIs that can draw to Surfaces.</p> * * <p>Note that creating a new capture session with {@link CameraDevice#createCaptureSession} * will close any existing capture session automatically, and call the older session listener's * {@link StateCallback#onClosed} callback. Using {@link CameraDevice#createCaptureSession} * directly without closing is the recommended approach for quickly switching to a new session, * since unchanged target outputs can be reused more efficiently.</p> * * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and any * repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). * However, any in-progress capture requests submitted to the session will be completed as * normal; once all captures have completed and the session has been torn down, * {@link StateCallback#onClosed} will be called.</p> * * <p>Closing a session is idempotent; closing more than once has no effect.</p> */ @Override public abstract void close(); /** * A callback object for receiving updates about the state of a camera capture session. * */ public static abstract class StateCallback { /** * This method is called when the camera device has finished configuring itself, and the * session can start processing capture requests. * * <p>If there are capture requests already queued with the session, they will start * processing once this callback is invoked, and the session will call {@link #onActive} * right after this callback is invoked.</p> * * <p>If no capture requests have been submitted, then the session will invoke * {@link #onReady} right after this callback.</p> * * <p>If the camera device configuration fails, then {@link #onConfigureFailed} will * be invoked instead of this callback.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} */ public abstract void onConfigured(@NonNull CameraCaptureSession session); /** * This method is called if the session cannot be configured as requested. * * <p>This can happen if the set of requested outputs contains unsupported sizes, * or too many outputs are requested at once.</p> * * <p>The session is considered to be closed, and all methods called on it after this * callback is invoked will throw an IllegalStateException. Any capture requests submitted * to the session prior to this callback will be discarded and will not produce any * callbacks on their listeners.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} */ public abstract void onConfigureFailed(@NonNull CameraCaptureSession session); /** * This method is called every time the session has no more capture requests to process. * * <p>During the creation of a new session, this callback is invoked right after * {@link #onConfigured} if no capture requests were submitted to the session prior to it * completing configuration.</p> * * <p>Otherwise, this callback will be invoked any time the session finishes processing * all of its active capture requests, and no repeating request or burst is set up.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * */ public void onReady(@NonNull CameraCaptureSession session) { // default empty implementation } /** * This method is called when the session starts actively processing capture requests. * * <p>If capture requests are submitted prior to {@link #onConfigured} being called, * then the session will start processing those requests immediately after the callback, * and this method will be immediately called after {@link #onConfigured}. * * <p>If the session runs out of capture requests to process and calls {@link #onReady}, * then this callback will be invoked again once new requests are submitted for capture.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} */ public void onActive(@NonNull CameraCaptureSession session) { // default empty implementation } /** * This method is called when camera device's input capture queue becomes empty, * and is ready to accept the next request. * * <p>Pending capture requests exist in one of two queues: the in-flight queue where requests * are already in different stages of processing pipeline, and an input queue where requests * wait to enter the in-flight queue. The input queue is needed because more requests may be * submitted than the current camera device pipeline depth.</p> * * <p>This callback is fired when the input queue becomes empty, and the camera device may * have to fall back to the repeating request if set, or completely skip the next frame from * the sensor. This can cause glitches to camera preview output, for example. This callback * will only fire after requests queued by capture() or captureBurst(), not after a * repeating request or burst enters the in-flight queue. For example, in the common case * of a repeating request and a single-shot JPEG capture, this callback only fires when the * JPEG request has entered the in-flight queue for capture.</p> * * <p>By only sending a new {@link #capture} or {@link #captureBurst} when the input * queue is empty, pipeline latency can be minimized.</p> * * <p>This callback is not fired when the session is first created. It is different from * {@link #onReady}, which is fired when all requests in both queues have been processed.</p> * * @param session * The session returned by {@link CameraDevice#createCaptureSession} */ public void onCaptureQueueEmpty(@NonNull CameraCaptureSession session) { // default empty implementation } /** * This method is called when the session is closed. * * <p>A session is closed when a new session is created by the parent camera device, * or when the parent camera device is closed (either by the user closing the device, * or due to a camera device disconnection or fatal error).</p> * * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and * any repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). * However, any in-progress capture requests submitted to the session will be completed * as normal.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} */ public void onClosed(@NonNull CameraCaptureSession session) { // default empty implementation } /** * This method is called when the buffer pre-allocation for an output Surface is complete. * * <p>Buffer pre-allocation for an output Surface is started by the {@link #prepare} call. * While allocation is underway, the Surface must not be used as a capture target. * Once this callback fires, the output Surface provided can again be used as a target for * a capture request.</p> * * <p>In case of a error during pre-allocation (such as running out of suitable memory), * this callback is still invoked after the error is encountered, though some buffers may * not have been successfully pre-allocated.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param surface the Surface that was used with the {@link #prepare} call. */ public void onSurfacePrepared(@NonNull CameraCaptureSession session, @NonNull Surface surface) { // default empty implementation } } /** * <p>A callback object for tracking the progress of a {@link CaptureRequest} submitted to the * camera device.</p> * * <p>This callback is invoked when a request triggers a capture to start, * and when the capture is complete. In case on an error capturing an image, * the error method is triggered instead of the completion method.</p> * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst */ public static abstract class CaptureCallback { /** * This constant is used to indicate that no images were captured for * the request. * * @hide */ public static final int NO_FRAMES_CAPTURED = -1; /** * This method is called when the camera device has started capturing * the output image for the request, at the beginning of image exposure, or * when the camera device has started processing an input image for a reprocess * request. * * <p>For a regular capture request, this callback is invoked right as * the capture of a frame begins, so it is the most appropriate time * for playing a shutter sound, or triggering UI indicators of capture.</p> * * <p>The request that is being used for this capture is provided, along * with the actual timestamp for the start of exposure. For a reprocess * request, this timestamp will be the input image's start of exposure * which matches {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field} * of the {@link TotalCaptureResult} that was used to * {@link CameraDevice#createReprocessCaptureRequest create the reprocess request}. * This timestamp matches the timestamps that will be * included in {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field}, * and in the buffers sent to each output Surface. These buffer * timestamps are accessible through, for example, * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or * {@link android.graphics.SurfaceTexture#getTimestamp()}. * The frame number included is equal to the frame number that will be included in * {@link CaptureResult#getFrameNumber}.</p> * * <p>For the simplest way to play a shutter sound camera shutter or a * video recording start/stop sound, see the * {@link android.media.MediaActionSound} class.</p> * * <p>The default implementation of this method does nothing.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param request the request for the capture that just begun * @param timestamp the timestamp at start of capture for a regular request, or * the timestamp at the input image's start of capture for a * reprocess request, in nanoseconds. * @param frameNumber the frame number for this capture * * @see android.media.MediaActionSound */ public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { // default empty implementation } /** * This method is called when some results from an image capture are * available. * * <p>The result provided here will contain some subset of the fields of * a full result. Multiple onCapturePartial calls may happen per * capture; a given result field will only be present in one partial * capture at most. The final onCaptureCompleted call will always * contain all the fields, whether onCapturePartial was called or * not.</p> * * <p>The default implementation of this method does nothing.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param request The request that was given to the CameraDevice * @param result The partial output metadata from the capture, which * includes a subset of the CaptureResult fields. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst * * @hide */ public void onCapturePartial(CameraCaptureSession session, CaptureRequest request, CaptureResult result) { // default empty implementation } /** * This method is called when an image capture makes partial forward progress; some * (but not all) results from an image capture are available. * * <p>The result provided here will contain some subset of the fields of * a full result. Multiple {@link #onCaptureProgressed} calls may happen per * capture; a given result field will only be present in one partial * capture at most. The final {@link #onCaptureCompleted} call will always * contain all the fields (in particular, the union of all the fields of all * the partial results composing the total result).</p> * * <p>For each request, some result data might be available earlier than others. The typical * delay between each partial result (per request) is a single frame interval. * For performance-oriented use-cases, applications should query the metadata they need * to make forward progress from the partial results and avoid waiting for the completed * result.</p> * * <p>For a particular request, {@link #onCaptureProgressed} may happen before or after * {@link #onCaptureStarted}.</p> * * <p>Each request will generate at least {@code 1} partial results, and at most * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p> * * <p>Depending on the request settings, the number of partial results per request * will vary, although typically the partial count could be the same as long as the * camera device subsystems enabled stay the same.</p> * * <p>The default implementation of this method does nothing.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param request The request that was given to the CameraDevice * @param partialResult The partial output metadata from the capture, which * includes a subset of the {@link TotalCaptureResult} fields. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst */ public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { // default empty implementation } /** * This method is called when an image capture has fully completed and all the * result metadata is available. * * <p>This callback will always fire after the last {@link #onCaptureProgressed}; * in other words, no more partial results will be delivered once the completed result * is available.</p> * * <p>For performance-intensive use-cases where latency is a factor, consider * using {@link #onCaptureProgressed} instead.</p> * * <p>The default implementation of this method does nothing.</p> * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param request The request that was given to the CameraDevice * @param result The total output metadata from the capture, including the * final capture parameters and the state of the camera system during * capture. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst */ public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { // default empty implementation } /** * This method is called instead of {@link #onCaptureCompleted} when the * camera device failed to produce a {@link CaptureResult} for the * request. * * <p>Other requests are unaffected, and some or all image buffers from * the capture may have been pushed to their respective output * streams.</p> * * <p>The default implementation of this method does nothing.</p> * * @param session * The session returned by {@link CameraDevice#createCaptureSession} * @param request * The request that was given to the CameraDevice * @param failure * The output failure from the capture, including the failure reason * and the frame number. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst */ public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { // default empty implementation } /** * This method is called independently of the others in CaptureCallback, * when a capture sequence finishes and all {@link CaptureResult} * or {@link CaptureFailure} for it have been returned via this listener. * * <p>In total, there will be at least one result/failure returned by this listener * before this callback is invoked. If the capture sequence is aborted before any * requests have been processed, {@link #onCaptureSequenceAborted} is invoked instead.</p> * * <p>The default implementation does nothing.</p> * * @param session * The session returned by {@link CameraDevice#createCaptureSession} * @param sequenceId * A sequence ID returned by the {@link #capture} family of functions. * @param frameNumber * The last frame number (returned by {@link CaptureResult#getFrameNumber} * or {@link CaptureFailure#getFrameNumber}) in the capture sequence. * * @see CaptureResult#getFrameNumber() * @see CaptureFailure#getFrameNumber() * @see CaptureResult#getSequenceId() * @see CaptureFailure#getSequenceId() * @see #onCaptureSequenceAborted */ public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) { // default empty implementation } /** * This method is called independently of the others in CaptureCallback, * when a capture sequence aborts before any {@link CaptureResult} * or {@link CaptureFailure} for it have been returned via this listener. * * <p>Due to the asynchronous nature of the camera device, not all submitted captures * are immediately processed. It is possible to clear out the pending requests * by a variety of operations such as {@link CameraCaptureSession#stopRepeating} or * {@link CameraCaptureSession#abortCaptures}. When such an event happens, * {@link #onCaptureSequenceCompleted} will not be called.</p> * * <p>The default implementation does nothing.</p> * * @param session * The session returned by {@link CameraDevice#createCaptureSession} * @param sequenceId * A sequence ID returned by the {@link #capture} family of functions. * * @see CaptureResult#getFrameNumber() * @see CaptureFailure#getFrameNumber() * @see CaptureResult#getSequenceId() * @see CaptureFailure#getSequenceId() * @see #onCaptureSequenceCompleted */ public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) { // default empty implementation } /** * <p>This method is called if a single buffer for a capture could not be sent to its * destination surface.</p> * * <p>If the whole capture failed, then {@link #onCaptureFailed} will be called instead. If * some but not all buffers were captured but the result metadata will not be available, * then onCaptureFailed will be invoked with {@link CaptureFailure#wasImageCaptured} * returning true, along with one or more calls to {@link #onCaptureBufferLost} for the * failed outputs.</p> * * @param session * The session returned by {@link CameraDevice#createCaptureSession} * @param request * The request that was given to the CameraDevice * @param target * The target Surface that the buffer will not be produced for * @param frameNumber * The frame number for the request */ public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { // default empty implementation } } }