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