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, null); 113 } 114 return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(), 115 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(), 116 /*partialResultCount*/1, errorStreamId, null); 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 return configureOutputs(outputs, /*validateSurfacesOnly*/false); 350 } 351 352 /** 353 * Configure the device with a set of output surfaces. 354 * 355 * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p> 356 * 357 * <p>Every surface in {@code outputs} must be non-{@code null}.</p> 358 * 359 * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this 360 * list; it must not be modified by the caller once it's passed in. 361 * @param validateSurfacesOnly If set it will only check whether the outputs are supported 362 * and avoid any device configuration. 363 * @return an error code for this binder operation, or {@link NO_ERROR} 364 * on success. 365 * @hide 366 */ configureOutputs(SparseArray<Surface> outputs, boolean validateSurfacesOnly)367 public int configureOutputs(SparseArray<Surface> outputs, boolean validateSurfacesOnly) { 368 List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>(); 369 if (outputs != null) { 370 int count = outputs.size(); 371 for (int i = 0; i < count; i++) { 372 Surface output = outputs.valueAt(i); 373 if (output == null) { 374 Log.e(TAG, "configureOutputs - null outputs are not allowed"); 375 return BAD_VALUE; 376 } 377 if (!output.isValid()) { 378 Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed"); 379 return BAD_VALUE; 380 } 381 StreamConfigurationMap streamConfigurations = mStaticCharacteristics. 382 get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 383 384 // Validate surface size and format. 385 try { 386 Size s = getSurfaceSize(output); 387 int surfaceType = detectSurfaceType(output); 388 389 boolean flexibleConsumer = isFlexibleConsumer(output); 390 391 Size[] sizes = streamConfigurations.getOutputSizes(surfaceType); 392 if (sizes == null) { 393 if (surfaceType == ImageFormat.PRIVATE) { 394 395 // YUV_420_888 is always present in LEGACY for all 396 // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the 397 // API (i.e. {@code #getOutputSizes} works here). 398 sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888); 399 } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) { 400 sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG); 401 } 402 } 403 404 if (!ArrayUtils.contains(sizes, s)) { 405 if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) { 406 sizedSurfaces.add(new Pair<>(output, s)); 407 } else { 408 String reason = (sizes == null) ? "format is invalid." : 409 ("size not in valid set: " + Arrays.toString(sizes)); 410 Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " + 411 "0x%x is not valid, %s", s.getWidth(), s.getHeight(), 412 surfaceType, reason)); 413 return BAD_VALUE; 414 } 415 } else { 416 sizedSurfaces.add(new Pair<>(output, s)); 417 } 418 // Lock down the size before configuration 419 if (!validateSurfacesOnly) { 420 setSurfaceDimens(output, s.getWidth(), s.getHeight()); 421 } 422 } catch (BufferQueueAbandonedException e) { 423 Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e); 424 return BAD_VALUE; 425 } 426 427 } 428 } 429 430 if (validateSurfacesOnly) { 431 return LegacyExceptionUtils.NO_ERROR; 432 } 433 434 boolean success = false; 435 if (mDeviceState.setConfiguring()) { 436 mRequestThreadManager.configure(sizedSurfaces); 437 success = mDeviceState.setIdle(); 438 } 439 440 if (success) { 441 mConfiguredSurfaces = outputs; 442 } else { 443 return LegacyExceptionUtils.INVALID_OPERATION; 444 } 445 return LegacyExceptionUtils.NO_ERROR; 446 } 447 448 /** 449 * Submit a burst of capture requests. 450 * 451 * @param requestList a list of capture requests to execute. 452 * @param repeating {@code true} if this burst is repeating. 453 * @return the submission info, including the new request id, and the last frame number, which 454 * contains either the frame number of the last frame that will be returned for this request, 455 * or the frame number of the last frame that will be returned for the current repeating 456 * request if this burst is set to be repeating. 457 */ submitRequestList(CaptureRequest[] requestList, boolean repeating)458 public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) { 459 if (requestList == null || requestList.length == 0) { 460 Log.e(TAG, "submitRequestList - Empty/null requests are not allowed"); 461 throw new ServiceSpecificException(BAD_VALUE, 462 "submitRequestList - Empty/null requests are not allowed"); 463 } 464 465 List<Long> surfaceIds; 466 467 try { 468 surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() : 469 getSurfaceIds(mConfiguredSurfaces); 470 } catch (BufferQueueAbandonedException e) { 471 throw new ServiceSpecificException(BAD_VALUE, 472 "submitRequestList - configured surface is abandoned."); 473 } 474 475 // Make sure that there all requests have at least 1 surface; all surfaces are non-null 476 for (CaptureRequest request : requestList) { 477 if (request.getTargets().isEmpty()) { 478 Log.e(TAG, "submitRequestList - " 479 + "Each request must have at least one Surface target"); 480 throw new ServiceSpecificException(BAD_VALUE, 481 "submitRequestList - " 482 + "Each request must have at least one Surface target"); 483 } 484 485 for (Surface surface : request.getTargets()) { 486 if (surface == null) { 487 Log.e(TAG, "submitRequestList - Null Surface targets are not allowed"); 488 throw new ServiceSpecificException(BAD_VALUE, 489 "submitRequestList - Null Surface targets are not allowed"); 490 } else if (mConfiguredSurfaces == null) { 491 Log.e(TAG, "submitRequestList - must configure " + 492 " device with valid surfaces before submitting requests"); 493 throw new ServiceSpecificException(INVALID_OPERATION, 494 "submitRequestList - must configure " + 495 " device with valid surfaces before submitting requests"); 496 } else if (!containsSurfaceId(surface, surfaceIds)) { 497 Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured"); 498 throw new ServiceSpecificException(BAD_VALUE, 499 "submitRequestList - cannot use a surface that wasn't configured"); 500 } 501 } 502 } 503 504 // TODO: further validation of request here 505 mIdle.close(); 506 return mRequestThreadManager.submitCaptureRequests(requestList, repeating); 507 } 508 509 /** 510 * Submit a single capture request. 511 * 512 * @param request the capture request to execute. 513 * @param repeating {@code true} if this request is repeating. 514 * @return the submission info, including the new request id, and the last frame number, which 515 * contains either the frame number of the last frame that will be returned for this request, 516 * or the frame number of the last frame that will be returned for the current repeating 517 * request if this burst is set to be repeating. 518 */ submitRequest(CaptureRequest request, boolean repeating)519 public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) { 520 CaptureRequest[] requestList = { request }; 521 return submitRequestList(requestList, repeating); 522 } 523 524 /** 525 * Cancel the repeating request with the given request id. 526 * 527 * @param requestId the request id of the request to cancel. 528 * @return the last frame number to be returned from the HAL for the given repeating request, or 529 * {@code INVALID_FRAME} if none exists. 530 */ cancelRequest(int requestId)531 public long cancelRequest(int requestId) { 532 return mRequestThreadManager.cancelRepeating(requestId); 533 } 534 535 /** 536 * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received. 537 */ waitUntilIdle()538 public void waitUntilIdle() { 539 mIdle.block(); 540 } 541 542 /** 543 * Flush any pending requests. 544 * 545 * @return the last frame number. 546 */ flush()547 public long flush() { 548 long lastFrame = mRequestThreadManager.flush(); 549 waitUntilIdle(); 550 return lastFrame; 551 } 552 553 /** 554 * Return {@code true} if the device has been closed. 555 */ isClosed()556 public boolean isClosed() { 557 return mClosed; 558 } 559 560 @Override close()561 public void close() { 562 mRequestThreadManager.quit(); 563 mCallbackHandlerThread.quitSafely(); 564 mResultThread.quitSafely(); 565 566 try { 567 mCallbackHandlerThread.join(); 568 } catch (InterruptedException e) { 569 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", 570 mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId())); 571 } 572 573 try { 574 mResultThread.join(); 575 } catch (InterruptedException e) { 576 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", 577 mResultThread.getName(), mResultThread.getId())); 578 } 579 580 mClosed = true; 581 } 582 583 @Override finalize()584 protected void finalize() throws Throwable { 585 try { 586 close(); 587 } catch (ServiceSpecificException e) { 588 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage()); 589 } finally { 590 super.finalize(); 591 } 592 } 593 findEuclidDistSquare(Size a, Size b)594 static long findEuclidDistSquare(Size a, Size b) { 595 long d0 = a.getWidth() - b.getWidth(); 596 long d1 = a.getHeight() - b.getHeight(); 597 return d0 * d0 + d1 * d1; 598 } 599 600 // Keep up to date with rounding behavior in 601 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp findClosestSize(Size size, Size[] supportedSizes)602 static Size findClosestSize(Size size, Size[] supportedSizes) { 603 if (size == null || supportedSizes == null) { 604 return null; 605 } 606 Size bestSize = null; 607 for (Size s : supportedSizes) { 608 if (s.equals(size)) { 609 return size; 610 } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null || 611 LegacyCameraDevice.findEuclidDistSquare(size, s) < 612 LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) { 613 bestSize = s; 614 } 615 } 616 return bestSize; 617 } 618 619 /** 620 * Query the surface for its currently configured default buffer size. 621 * @param surface a non-{@code null} {@code Surface} 622 * @return the width and height of the surface 623 * 624 * @throws NullPointerException if the {@code surface} was {@code null} 625 * @throws BufferQueueAbandonedException if the {@code surface} was invalid 626 */ getSurfaceSize(Surface surface)627 public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException { 628 checkNotNull(surface); 629 630 int[] dimens = new int[2]; 631 LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens)); 632 633 return new Size(dimens[0], dimens[1]); 634 } 635 isFlexibleConsumer(Surface output)636 public static boolean isFlexibleConsumer(Surface output) { 637 int usageFlags = detectSurfaceUsageFlags(output); 638 639 // Keep up to date with allowed consumer types in 640 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp 641 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT; 642 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN | 643 GRALLOC_USAGE_HW_COMPOSER; 644 boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 && 645 (usageFlags & allowedFlags) != 0); 646 return flexibleConsumer; 647 } 648 isPreviewConsumer(Surface output)649 public static boolean isPreviewConsumer(Surface output) { 650 int usageFlags = detectSurfaceUsageFlags(output); 651 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT | 652 GRALLOC_USAGE_SW_READ_OFTEN; 653 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | 654 GRALLOC_USAGE_HW_RENDER; 655 boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 && 656 (usageFlags & allowedFlags) != 0); 657 int surfaceFormat = ImageFormat.UNKNOWN; 658 try { 659 surfaceFormat = detectSurfaceType(output); 660 } catch(BufferQueueAbandonedException e) { 661 throw new IllegalArgumentException("Surface was abandoned", e); 662 } 663 664 return previewConsumer; 665 } 666 isVideoEncoderConsumer(Surface output)667 public static boolean isVideoEncoderConsumer(Surface output) { 668 int usageFlags = detectSurfaceUsageFlags(output); 669 int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | 670 GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN; 671 int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER; 672 boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 && 673 (usageFlags & allowedFlags) != 0); 674 675 int surfaceFormat = ImageFormat.UNKNOWN; 676 try { 677 surfaceFormat = detectSurfaceType(output); 678 } catch(BufferQueueAbandonedException e) { 679 throw new IllegalArgumentException("Surface was abandoned", e); 680 } 681 682 return videoEncoderConsumer; 683 } 684 685 /** 686 * Query the surface for its currently configured usage flags 687 */ detectSurfaceUsageFlags(Surface surface)688 static int detectSurfaceUsageFlags(Surface surface) { 689 checkNotNull(surface); 690 return nativeDetectSurfaceUsageFlags(surface); 691 } 692 693 /** 694 * Query the surface for its currently configured format 695 */ detectSurfaceType(Surface surface)696 public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException { 697 checkNotNull(surface); 698 int surfaceType = nativeDetectSurfaceType(surface); 699 700 // TODO: remove this override since the default format should be 701 // ImageFormat.PRIVATE. b/9487482 702 if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 && 703 surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) { 704 surfaceType = ImageFormat.PRIVATE; 705 } 706 707 return LegacyExceptionUtils.throwOnError(surfaceType); 708 } 709 710 /** 711 * Query the surface for its currently configured dataspace 712 */ detectSurfaceDataspace(Surface surface)713 public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException { 714 checkNotNull(surface); 715 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface)); 716 } 717 connectSurface(Surface surface)718 static void connectSurface(Surface surface) throws BufferQueueAbandonedException { 719 checkNotNull(surface); 720 721 LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface)); 722 } 723 disconnectSurface(Surface surface)724 static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException { 725 if (surface == null) return; 726 727 LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface)); 728 } 729 produceFrame(Surface surface, byte[] pixelBuffer, int width, int height, int pixelFormat)730 static void produceFrame(Surface surface, byte[] pixelBuffer, int width, 731 int height, int pixelFormat) 732 throws BufferQueueAbandonedException { 733 checkNotNull(surface); 734 checkNotNull(pixelBuffer); 735 checkArgumentPositive(width, "width must be positive."); 736 checkArgumentPositive(height, "height must be positive."); 737 738 LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height, 739 pixelFormat)); 740 } 741 setSurfaceFormat(Surface surface, int pixelFormat)742 static void setSurfaceFormat(Surface surface, int pixelFormat) 743 throws BufferQueueAbandonedException { 744 checkNotNull(surface); 745 746 LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat)); 747 } 748 setSurfaceDimens(Surface surface, int width, int height)749 static void setSurfaceDimens(Surface surface, int width, int height) 750 throws BufferQueueAbandonedException { 751 checkNotNull(surface); 752 checkArgumentPositive(width, "width must be positive."); 753 checkArgumentPositive(height, "height must be positive."); 754 755 LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height)); 756 } 757 getSurfaceId(Surface surface)758 public static long getSurfaceId(Surface surface) throws BufferQueueAbandonedException { 759 checkNotNull(surface); 760 try { 761 return nativeGetSurfaceId(surface); 762 } catch (IllegalArgumentException e) { 763 throw new BufferQueueAbandonedException(); 764 } 765 } 766 getSurfaceIds(SparseArray<Surface> surfaces)767 static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) 768 throws BufferQueueAbandonedException { 769 if (surfaces == null) { 770 throw new NullPointerException("Null argument surfaces"); 771 } 772 List<Long> surfaceIds = new ArrayList<>(); 773 int count = surfaces.size(); 774 for (int i = 0; i < count; i++) { 775 long id = getSurfaceId(surfaces.valueAt(i)); 776 if (id == 0) { 777 throw new IllegalStateException( 778 "Configured surface had null native GraphicBufferProducer pointer!"); 779 } 780 surfaceIds.add(id); 781 } 782 return surfaceIds; 783 } 784 getSurfaceIds(Collection<Surface> surfaces)785 static List<Long> getSurfaceIds(Collection<Surface> surfaces) 786 throws BufferQueueAbandonedException { 787 if (surfaces == null) { 788 throw new NullPointerException("Null argument surfaces"); 789 } 790 List<Long> surfaceIds = new ArrayList<>(); 791 for (Surface s : surfaces) { 792 long id = getSurfaceId(s); 793 if (id == 0) { 794 throw new IllegalStateException( 795 "Configured surface had null native GraphicBufferProducer pointer!"); 796 } 797 surfaceIds.add(id); 798 } 799 return surfaceIds; 800 } 801 containsSurfaceId(Surface s, Collection<Long> ids)802 static boolean containsSurfaceId(Surface s, Collection<Long> ids) { 803 long id = 0; 804 try { 805 id = getSurfaceId(s); 806 } catch (BufferQueueAbandonedException e) { 807 // If surface is abandoned, return false. 808 return false; 809 } 810 return ids.contains(id); 811 } 812 setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)813 static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation) 814 throws BufferQueueAbandonedException { 815 checkNotNull(surface); 816 LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing, 817 sensorOrientation)); 818 } 819 getTextureSize(SurfaceTexture surfaceTexture)820 static Size getTextureSize(SurfaceTexture surfaceTexture) 821 throws BufferQueueAbandonedException { 822 checkNotNull(surfaceTexture); 823 824 int[] dimens = new int[2]; 825 LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture, 826 /*out*/dimens)); 827 828 return new Size(dimens[0], dimens[1]); 829 } 830 setNextTimestamp(Surface surface, long timestamp)831 static void setNextTimestamp(Surface surface, long timestamp) 832 throws BufferQueueAbandonedException { 833 checkNotNull(surface); 834 LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp)); 835 } 836 setScalingMode(Surface surface, int mode)837 static void setScalingMode(Surface surface, int mode) 838 throws BufferQueueAbandonedException { 839 checkNotNull(surface); 840 LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode)); 841 } 842 843 nativeDetectSurfaceType(Surface surface)844 private static native int nativeDetectSurfaceType(Surface surface); 845 nativeDetectSurfaceDataspace(Surface surface)846 private static native int nativeDetectSurfaceDataspace(Surface surface); 847 nativeDetectSurfaceDimens(Surface surface, int[ ] dimens)848 private static native int nativeDetectSurfaceDimens(Surface surface, 849 /*out*/int[/*2*/] dimens); 850 nativeConnectSurface(Surface surface)851 private static native int nativeConnectSurface(Surface surface); 852 nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width, int height, int pixelFormat)853 private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width, 854 int height, int pixelFormat); 855 nativeSetSurfaceFormat(Surface surface, int pixelFormat)856 private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat); 857 nativeSetSurfaceDimens(Surface surface, int width, int height)858 private static native int nativeSetSurfaceDimens(Surface surface, int width, int height); 859 nativeGetSurfaceId(Surface surface)860 private static native long nativeGetSurfaceId(Surface surface); 861 nativeSetSurfaceOrientation(Surface surface, int facing, int sensorOrientation)862 private static native int nativeSetSurfaceOrientation(Surface surface, int facing, 863 int sensorOrientation); 864 nativeDetectTextureDimens(SurfaceTexture surfaceTexture, int[ ] dimens)865 private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture, 866 /*out*/int[/*2*/] dimens); 867 nativeSetNextTimestamp(Surface surface, long timestamp)868 private static native int nativeSetNextTimestamp(Surface surface, long timestamp); 869 nativeDetectSurfaceUsageFlags(Surface surface)870 private static native int nativeDetectSurfaceUsageFlags(Surface surface); 871 nativeSetScalingMode(Surface surface, int scalingMode)872 private static native int nativeSetScalingMode(Surface surface, int scalingMode); 873 nativeDisconnectSurface(Surface surface)874 private static native int nativeDisconnectSurface(Surface surface); 875 nativeGetJpegFooterSize()876 static native int nativeGetJpegFooterSize(); 877 } 878