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