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