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