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