LegacyCameraDevice.java revision 3e0023ae89895f215791a8472f22b213f5a9ae93
1/* 2 * Copyright (C) 2014 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 17package android.hardware.camera2.legacy; 18 19import android.graphics.ImageFormat; 20import android.graphics.SurfaceTexture; 21import android.hardware.Camera; 22import android.hardware.camera2.CameraCharacteristics; 23import android.hardware.camera2.CaptureRequest; 24import android.hardware.camera2.impl.CameraDeviceImpl; 25import android.hardware.camera2.impl.CaptureResultExtras; 26import android.hardware.camera2.ICameraDeviceCallbacks; 27import android.hardware.camera2.params.StreamConfigurationMap; 28import android.hardware.camera2.utils.ArrayUtils; 29import android.hardware.camera2.utils.SubmitInfo; 30import android.hardware.camera2.impl.CameraMetadataNative; 31import android.os.ConditionVariable; 32import android.os.Handler; 33import android.os.HandlerThread; 34import android.os.RemoteException; 35import android.os.ServiceSpecificException; 36import android.util.Log; 37import android.util.Pair; 38import android.util.Size; 39import android.view.Surface; 40 41import java.util.ArrayList; 42import java.util.Arrays; 43import java.util.Collection; 44import java.util.List; 45 46import static android.hardware.camera2.legacy.LegacyExceptionUtils.*; 47import static com.android.internal.util.Preconditions.*; 48 49/** 50 * This class emulates the functionality of a Camera2 device using a the old Camera class. 51 * 52 * <p> 53 * There are two main components that are used to implement this: 54 * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}). 55 * - A message-queue based pipeline that manages an old Camera class, and executes capture and 56 * configuration requests. 57 * </p> 58 */ 59public class LegacyCameraDevice implements AutoCloseable { 60 private final String TAG; 61 62 private static final boolean DEBUG = false; 63 private final int mCameraId; 64 private final CameraCharacteristics mStaticCharacteristics; 65 private final ICameraDeviceCallbacks mDeviceCallbacks; 66 private final CameraDeviceState mDeviceState = new CameraDeviceState(); 67 private List<Surface> mConfiguredSurfaces; 68 private boolean mClosed = false; 69 70 private final ConditionVariable mIdle = new ConditionVariable(/*open*/true); 71 72 private final HandlerThread mResultThread = new HandlerThread("ResultThread"); 73 private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread"); 74 private final Handler mCallbackHandler; 75 private final Handler mResultHandler; 76 private static final int ILLEGAL_VALUE = -1; 77 78 // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h 79 private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000; 80 private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003; 81 private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100; 82 private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800; 83 private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200; 84 private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000; 85 86 public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding 87 88 // Keep up to date with values in system/core/include/system/window.h 89 public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1; 90 91 private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) { 92 if (holder == null) { 93 return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, 94 ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE); 95 } 96 return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(), 97 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(), 98 /*partialResultCount*/1, /*errorStreamId*/-1); 99 } 100 101 /** 102 * Listener for the camera device state machine. Calls the appropriate 103 * {@link ICameraDeviceCallbacks} for each state transition. 104 */ 105 private final CameraDeviceState.CameraDeviceStateListener mStateListener = 106 new CameraDeviceState.CameraDeviceStateListener() { 107 @Override 108 public void onError(final int errorCode, final RequestHolder holder) { 109 if (DEBUG) { 110 Log.d(TAG, "onError called, errorCode = " + errorCode); 111 } 112 switch (errorCode) { 113 /* 114 * Only be considered idle if we hit a fatal error 115 * and no further requests can be processed. 116 */ 117 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED: 118 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE: 119 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: { 120 mIdle.open(); 121 122 if (DEBUG) { 123 Log.d(TAG, "onError - opening idle"); 124 } 125 } 126 } 127 128 final CaptureResultExtras extras = getExtrasFromRequest(holder); 129 mResultHandler.post(new Runnable() { 130 @Override 131 public void run() { 132 if (DEBUG) { 133 Log.d(TAG, "doing onError callback for request " + holder.getRequestId() + 134 ", with error code " + errorCode); 135 } 136 try { 137 mDeviceCallbacks.onDeviceError(errorCode, extras); 138 } catch (RemoteException e) { 139 throw new IllegalStateException( 140 "Received remote exception during onCameraError callback: ", e); 141 } 142 } 143 }); 144 } 145 146 @Override 147 public void onConfiguring() { 148 // Do nothing 149 if (DEBUG) { 150 Log.d(TAG, "doing onConfiguring callback."); 151 } 152 } 153 154 @Override 155 public void onIdle() { 156 if (DEBUG) { 157 Log.d(TAG, "onIdle called"); 158 } 159 160 mIdle.open(); 161 162 mResultHandler.post(new Runnable() { 163 @Override 164 public void run() { 165 if (DEBUG) { 166 Log.d(TAG, "doing onIdle callback."); 167 } 168 try { 169 mDeviceCallbacks.onDeviceIdle(); 170 } catch (RemoteException e) { 171 throw new IllegalStateException( 172 "Received remote exception during onCameraIdle callback: ", e); 173 } 174 } 175 }); 176 } 177 178 @Override 179 public void onBusy() { 180 mIdle.close(); 181 182 if (DEBUG) { 183 Log.d(TAG, "onBusy called"); 184 } 185 } 186 187 @Override 188 public void onCaptureStarted(final RequestHolder holder, final long timestamp) { 189 final CaptureResultExtras extras = getExtrasFromRequest(holder); 190 191 mResultHandler.post(new Runnable() { 192 @Override 193 public void run() { 194 if (DEBUG) { 195 Log.d(TAG, "doing onCaptureStarted callback for request " + 196 holder.getRequestId()); 197 } 198 try { 199 mDeviceCallbacks.onCaptureStarted(extras, timestamp); 200 } catch (RemoteException e) { 201 throw new IllegalStateException( 202 "Received remote exception during onCameraError callback: ", e); 203 } 204 } 205 }); 206 } 207 208 @Override 209 public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) { 210 final CaptureResultExtras extras = getExtrasFromRequest(holder); 211 212 mResultHandler.post(new Runnable() { 213 @Override 214 public void run() { 215 if (DEBUG) { 216 Log.d(TAG, "doing onCaptureResult callback for request " + 217 holder.getRequestId()); 218 } 219 try { 220 mDeviceCallbacks.onResultReceived(result, extras); 221 } catch (RemoteException e) { 222 throw new IllegalStateException( 223 "Received remote exception during onCameraError callback: ", e); 224 } 225 } 226 }); 227 } 228 }; 229 230 private final RequestThreadManager mRequestThreadManager; 231 232 /** 233 * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily 234 * converted to this; YV12 and NV21 are the two currently supported formats. 235 * 236 * @param s the surface to check. 237 * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible 238 * format. 239 */ 240 static boolean needsConversion(Surface s) throws BufferQueueAbandonedException { 241 int nativeType = detectSurfaceType(s); 242 return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 || 243 nativeType == ImageFormat.NV21; 244 } 245 246 /** 247 * Create a new emulated camera device from a given Camera 1 API camera. 248 * 249 * <p> 250 * The {@link Camera} provided to this constructor must already have been successfully opened, 251 * and ownership of the provided camera is passed to this object. No further calls to the 252 * camera methods should be made following this constructor. 253 * </p> 254 * 255 * @param cameraId the id of the camera. 256 * @param camera an open {@link Camera} device. 257 * @param characteristics the static camera characteristics for this camera device 258 * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations. 259 */ 260 public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics, 261 ICameraDeviceCallbacks callbacks) { 262 mCameraId = cameraId; 263 mDeviceCallbacks = callbacks; 264 TAG = String.format("CameraDevice-%d-LE", mCameraId); 265 266 mResultThread.start(); 267 mResultHandler = new Handler(mResultThread.getLooper()); 268 mCallbackHandlerThread.start(); 269 mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper()); 270 mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener); 271 mStaticCharacteristics = characteristics; 272 mRequestThreadManager = 273 new RequestThreadManager(cameraId, camera, characteristics, mDeviceState); 274 mRequestThreadManager.start(); 275 } 276 277 /** 278 * Configure the device with a set of output surfaces. 279 * 280 * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p> 281 * 282 * <p>Every surface in {@code outputs} must be non-{@code null}.</p> 283 * 284 * @param outputs a list of surfaces to set. 285 * @return an error code for this binder operation, or {@link NO_ERROR} 286 * on success. 287 */ 288 public int configureOutputs(List<Surface> outputs) { 289 List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>(); 290 if (outputs != null) { 291 for (Surface output : outputs) { 292 if (output == null) { 293 Log.e(TAG, "configureOutputs - null outputs are not allowed"); 294 return BAD_VALUE; 295 } 296 if (!output.isValid()) { 297 Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed"); 298 return BAD_VALUE; 299 } 300 StreamConfigurationMap streamConfigurations = mStaticCharacteristics. 301 get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 302 303 // Validate surface size and format. 304 try { 305 Size s = getSurfaceSize(output); 306 int surfaceType = detectSurfaceType(output); 307 308 boolean flexibleConsumer = isFlexibleConsumer(output); 309 310 Size[] sizes = streamConfigurations.getOutputSizes(surfaceType); 311 if (sizes == null) { 312 // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482 313 if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 && 314 surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) { 315 316 // YUV_420_888 is always present in LEGACY for all 317 // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the 318 // API (i.e. {@code #getOutputSizes} works here). 319 sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888); 320 } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) { 321 sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG); 322 } 323 } 324 325 if (!ArrayUtils.contains(sizes, s)) { 326 if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) { 327 sizedSurfaces.add(new Pair<>(output, s)); 328 } else { 329 String reason = (sizes == null) ? "format is invalid." : 330 ("size not in valid set: " + Arrays.toString(sizes)); 331 Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " + 332 "0x%x is not valid, %s", s.getWidth(), s.getHeight(), 333 surfaceType, reason)); 334 return BAD_VALUE; 335 } 336 } else { 337 sizedSurfaces.add(new Pair<>(output, s)); 338 } 339 // Lock down the size before configuration 340 setSurfaceDimens(output, s.getWidth(), s.getHeight()); 341 } catch (BufferQueueAbandonedException e) { 342 Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e); 343 return BAD_VALUE; 344 } 345 346 } 347 } 348 349 boolean success = false; 350 if (mDeviceState.setConfiguring()) { 351 mRequestThreadManager.configure(sizedSurfaces); 352 success = mDeviceState.setIdle(); 353 } 354 355 if (success) { 356 mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null; 357 } else { 358 return LegacyExceptionUtils.INVALID_OPERATION; 359 } 360 return LegacyExceptionUtils.NO_ERROR; 361 } 362 363 /** 364 * Submit a burst of capture requests. 365 * 366 * @param requestList a list of capture requests to execute. 367 * @param repeating {@code true} if this burst is repeating. 368 * @return the submission info, including the new request id, and the last frame number, which 369 * contains either the frame number of the last frame that will be returned for this request, 370 * or the frame number of the last frame that will be returned for the current repeating 371 * request if this burst is set to be repeating. 372 */ 373 public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) { 374 if (requestList == null || requestList.length == 0) { 375 Log.e(TAG, "submitRequestList - Empty/null requests are not allowed"); 376 throw new ServiceSpecificException(BAD_VALUE, 377 "submitRequestList - Empty/null requests are not allowed"); 378 } 379 380 List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() : 381 getSurfaceIds(mConfiguredSurfaces); 382 383 // Make sure that there all requests have at least 1 surface; all surfaces are non-null 384 for (CaptureRequest request : requestList) { 385 if (request.getTargets().isEmpty()) { 386 Log.e(TAG, "submitRequestList - " 387 + "Each request must have at least one Surface target"); 388 throw new ServiceSpecificException(BAD_VALUE, 389 "submitRequestList - " 390 + "Each request must have at least one Surface target"); 391 } 392 393 for (Surface surface : request.getTargets()) { 394 if (surface == null) { 395 Log.e(TAG, "submitRequestList - Null Surface targets are not allowed"); 396 throw new ServiceSpecificException(BAD_VALUE, 397 "submitRequestList - Null Surface targets are not allowed"); 398 } else if (mConfiguredSurfaces == null) { 399 Log.e(TAG, "submitRequestList - must configure " + 400 " device with valid surfaces before submitting requests"); 401 throw new ServiceSpecificException(INVALID_OPERATION, 402 "submitRequestList - must configure " + 403 " device with valid surfaces before submitting requests"); 404 } else if (!containsSurfaceId(surface, surfaceIds)) { 405 Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured"); 406 throw new ServiceSpecificException(BAD_VALUE, 407 "submitRequestList - cannot use a surface that wasn't configured"); 408 } 409 } 410 } 411 412 // TODO: further validation of request here 413 mIdle.close(); 414 return mRequestThreadManager.submitCaptureRequests(requestList, repeating); 415 } 416 417 /** 418 * Submit a single capture request. 419 * 420 * @param request the capture request to execute. 421 * @param repeating {@code true} if this request is repeating. 422 * @return the submission info, including the new request id, and the last frame number, which 423 * contains either the frame number of the last frame that will be returned for this request, 424 * or the frame number of the last frame that will be returned for the current repeating 425 * request if this burst is set to be repeating. 426 */ 427 public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) { 428 CaptureRequest[] requestList = { request }; 429 return submitRequestList(requestList, repeating); 430 } 431 432 /** 433 * Cancel the repeating request with the given request id. 434 * 435 * @param requestId the request id of the request to cancel. 436 * @return the last frame number to be returned from the HAL for the given repeating request, or 437 * {@code INVALID_FRAME} if none exists. 438 */ 439 public long cancelRequest(int requestId) { 440 return mRequestThreadManager.cancelRepeating(requestId); 441 } 442 443 /** 444 * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received. 445 */ 446 public void waitUntilIdle() { 447 mIdle.block(); 448 } 449 450 /** 451 * Flush any pending requests. 452 * 453 * @return the last frame number. 454 */ 455 public long flush() { 456 long lastFrame = mRequestThreadManager.flush(); 457 waitUntilIdle(); 458 return lastFrame; 459 } 460 461 /** 462 * Return {@code true} if the device has been closed. 463 */ 464 public boolean isClosed() { 465 return mClosed; 466 } 467 468 @Override 469 public void close() { 470 mRequestThreadManager.quit(); 471 mCallbackHandlerThread.quitSafely(); 472 mResultThread.quitSafely(); 473 474 try { 475 mCallbackHandlerThread.join(); 476 } catch (InterruptedException e) { 477 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", 478 mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId())); 479 } 480 481 try { 482 mResultThread.join(); 483 } catch (InterruptedException e) { 484 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", 485 mResultThread.getName(), mResultThread.getId())); 486 } 487 488 mClosed = true; 489 } 490 491 @Override 492 protected void finalize() throws Throwable { 493 try { 494 close(); 495 } catch (ServiceSpecificException e) { 496 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage()); 497 } finally { 498 super.finalize(); 499 } 500 } 501 502 static long findEuclidDistSquare(Size a, Size b) { 503 long d0 = a.getWidth() - b.getWidth(); 504 long d1 = a.getHeight() - b.getHeight(); 505 return d0 * d0 + d1 * d1; 506 } 507 508 // Keep up to date with rounding behavior in 509 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp 510 static Size findClosestSize(Size size, Size[] supportedSizes) { 511 if (size == null || supportedSizes == null) { 512 return null; 513 } 514 Size bestSize = null; 515 for (Size s : supportedSizes) { 516 if (s.equals(size)) { 517 return size; 518 } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null || 519 LegacyCameraDevice.findEuclidDistSquare(size, s) < 520 LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) { 521 bestSize = s; 522 } 523 } 524 return bestSize; 525 } 526 527 /** 528 * Query the surface for its currently configured default buffer size. 529 * @param surface a non-{@code null} {@code Surface} 530 * @return the width and height of the surface 531 * 532 * @throws NullPointerException if the {@code surface} was {@code null} 533 * @throws BufferQueueAbandonedException if the {@code surface} was invalid 534 */ 535 public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException { 536 checkNotNull(surface); 537 538 int[] dimens = new int[2]; 539 LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens)); 540 541 return new Size(dimens[0], dimens[1]); 542 } 543 544 public static boolean isFlexibleConsumer(Surface output) { 545 int usageFlags = detectSurfaceUsageFlags(output); 546 547 // Keep up to date with allowed consumer types in 548 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp 549 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT; 550 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN | 551 GRALLOC_USAGE_HW_COMPOSER; 552 boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 && 553 (usageFlags & allowedFlags) != 0); 554 return flexibleConsumer; 555 } 556 557 public static boolean isPreviewConsumer(Surface output) { 558 int usageFlags = detectSurfaceUsageFlags(output); 559 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT | 560 GRALLOC_USAGE_SW_READ_OFTEN; 561 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | 562 GRALLOC_USAGE_HW_RENDER; 563 boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 && 564 (usageFlags & allowedFlags) != 0); 565 int surfaceFormat = ImageFormat.UNKNOWN; 566 try { 567 surfaceFormat = detectSurfaceType(output); 568 } catch(BufferQueueAbandonedException e) { 569 throw new IllegalArgumentException("Surface was abandoned", e); 570 } 571 572 return previewConsumer; 573 } 574 575 public static boolean isVideoEncoderConsumer(Surface output) { 576 int usageFlags = detectSurfaceUsageFlags(output); 577 int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | 578 GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN; 579 int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER; 580 boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 && 581 (usageFlags & allowedFlags) != 0); 582 583 int surfaceFormat = ImageFormat.UNKNOWN; 584 try { 585 surfaceFormat = detectSurfaceType(output); 586 } catch(BufferQueueAbandonedException e) { 587 throw new IllegalArgumentException("Surface was abandoned", e); 588 } 589 590 return videoEncoderConsumer; 591 } 592 593 /** 594 * Query the surface for its currently configured usage flags 595 */ 596 static int detectSurfaceUsageFlags(Surface surface) { 597 checkNotNull(surface); 598 return nativeDetectSurfaceUsageFlags(surface); 599 } 600 601 /** 602 * Query the surface for its currently configured format 603 */ 604 public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException { 605 checkNotNull(surface); 606 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface)); 607 } 608 609 /** 610 * Query the surface for its currently configured dataspace 611 */ 612 public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException { 613 checkNotNull(surface); 614 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface)); 615 } 616 617 static void connectSurface(Surface surface) throws BufferQueueAbandonedException { 618 checkNotNull(surface); 619 620 LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface)); 621 } 622 623 static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException { 624 if (surface == null) return; 625 626 LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface)); 627 } 628 629 static void produceFrame(Surface surface, byte[] pixelBuffer, int width, 630 int height, int pixelFormat) 631 throws BufferQueueAbandonedException { 632 checkNotNull(surface); 633 checkNotNull(pixelBuffer); 634 checkArgumentPositive(width, "width must be positive."); 635 checkArgumentPositive(height, "height must be positive."); 636 637 LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height, 638 pixelFormat)); 639 } 640 641 static void setSurfaceFormat(Surface surface, int pixelFormat) 642 throws BufferQueueAbandonedException { 643 checkNotNull(surface); 644 645 LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat)); 646 } 647 648 static void setSurfaceDimens(Surface surface, int width, int height) 649 throws BufferQueueAbandonedException { 650 checkNotNull(surface); 651 checkArgumentPositive(width, "width must be positive."); 652 checkArgumentPositive(height, "height must be positive."); 653 654 LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height)); 655 } 656 657 static long getSurfaceId(Surface surface) { 658 checkNotNull(surface); 659 return nativeGetSurfaceId(surface); 660 } 661 662 static List<Long> getSurfaceIds(Collection<Surface> surfaces) { 663 if (surfaces == null) { 664 throw new NullPointerException("Null argument surfaces"); 665 } 666 List<Long> surfaceIds = new ArrayList<>(); 667 for (Surface s : surfaces) { 668 long id = getSurfaceId(s); 669 if (id == 0) { 670 throw new IllegalStateException( 671 "Configured surface had null native GraphicBufferProducer pointer!"); 672 } 673 surfaceIds.add(id); 674 } 675 return surfaceIds; 676 } 677 678 static boolean containsSurfaceId(Surface s, Collection<Long> ids) { 679 long id = getSurfaceId(s); 680 return ids.contains(id); 681 } 682 683 static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation) 684 throws BufferQueueAbandonedException { 685 checkNotNull(surface); 686 LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing, 687 sensorOrientation)); 688 } 689 690 static Size getTextureSize(SurfaceTexture surfaceTexture) 691 throws BufferQueueAbandonedException { 692 checkNotNull(surfaceTexture); 693 694 int[] dimens = new int[2]; 695 LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture, 696 /*out*/dimens)); 697 698 return new Size(dimens[0], dimens[1]); 699 } 700 701 static void setNextTimestamp(Surface surface, long timestamp) 702 throws BufferQueueAbandonedException { 703 checkNotNull(surface); 704 LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp)); 705 } 706 707 static void setScalingMode(Surface surface, int mode) 708 throws BufferQueueAbandonedException { 709 checkNotNull(surface); 710 LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode)); 711 } 712 713 714 private static native int nativeDetectSurfaceType(Surface surface); 715 716 private static native int nativeDetectSurfaceDataspace(Surface surface); 717 718 private static native int nativeDetectSurfaceDimens(Surface surface, 719 /*out*/int[/*2*/] dimens); 720 721 private static native int nativeConnectSurface(Surface surface); 722 723 private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width, 724 int height, int pixelFormat); 725 726 private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat); 727 728 private static native int nativeSetSurfaceDimens(Surface surface, int width, int height); 729 730 private static native long nativeGetSurfaceId(Surface surface); 731 732 private static native int nativeSetSurfaceOrientation(Surface surface, int facing, 733 int sensorOrientation); 734 735 private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture, 736 /*out*/int[/*2*/] dimens); 737 738 private static native int nativeSetNextTimestamp(Surface surface, long timestamp); 739 740 private static native int nativeDetectSurfaceUsageFlags(Surface surface); 741 742 private static native int nativeSetScalingMode(Surface surface, int scalingMode); 743 744 private static native int nativeDisconnectSurface(Surface surface); 745 746 static native int nativeGetJpegFooterSize(); 747} 748