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