1 /* 2 * Copyright 2015 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.media; 18 19 import android.annotation.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.SuppressLint; 22 import android.graphics.GraphicBuffer; 23 import android.graphics.ImageFormat; 24 import android.graphics.ImageFormat.Format; 25 import android.graphics.PixelFormat; 26 import android.graphics.Rect; 27 import android.hardware.DataSpace; 28 import android.hardware.DataSpace.NamedDataSpace; 29 import android.hardware.HardwareBuffer; 30 import android.hardware.HardwareBuffer.Usage; 31 import android.hardware.SyncFence; 32 import android.hardware.camera2.params.StreamConfigurationMap; 33 import android.hardware.camera2.utils.SurfaceUtils; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.ParcelFileDescriptor; 38 import android.util.Size; 39 import android.view.Surface; 40 41 import dalvik.system.VMRuntime; 42 43 import java.io.IOException; 44 import java.lang.ref.WeakReference; 45 import java.nio.ByteBuffer; 46 import java.nio.ByteOrder; 47 import java.nio.NioUtils; 48 import java.util.List; 49 import java.util.concurrent.CopyOnWriteArrayList; 50 51 /** 52 * <p> 53 * The ImageWriter class allows an application to produce Image data into a 54 * {@link android.view.Surface}, and have it be consumed by another component 55 * like {@link android.hardware.camera2.CameraDevice CameraDevice}. 56 * </p> 57 * <p> 58 * Several Android API classes can provide input {@link android.view.Surface 59 * Surface} objects for ImageWriter to produce data into, including 60 * {@link MediaCodec MediaCodec} (encoder), 61 * {@link android.hardware.camera2.CameraCaptureSession CameraCaptureSession} 62 * (reprocessing input), {@link ImageReader}, etc. 63 * </p> 64 * <p> 65 * The input Image data is encapsulated in {@link Image} objects. To produce 66 * Image data into a destination {@link android.view.Surface Surface}, the 67 * application can get an input Image via {@link #dequeueInputImage} then write 68 * Image data into it. Multiple such {@link Image} objects can be dequeued at 69 * the same time and queued back in any order, up to the number specified by the 70 * {@code maxImages} constructor parameter. 71 * </p> 72 * <p> 73 * If the application already has an Image from {@link ImageReader}, the 74 * application can directly queue this Image into the ImageWriter (via 75 * {@link #queueInputImage}), potentially with zero buffer copies. This 76 * even works if the image format of the ImageWriter is 77 * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only 78 * way to enqueue images into such an ImageWriter. Starting in Android P 79 * private images may also be accessed through their hardware buffers 80 * (when available) through the {@link Image#getHardwareBuffer()} method. 81 * Attempting to access the planes of a private image, will return an 82 * empty array. 83 * </p> 84 * <p> 85 * Once new input Images are queued into an ImageWriter, it's up to the 86 * downstream components (e.g. {@link ImageReader} or 87 * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the 88 * downstream components cannot consume the Images at least as fast as the 89 * ImageWriter production rate, the {@link #dequeueInputImage} call will 90 * eventually block and the application will have to drop input frames. 91 * </p> 92 * <p> 93 * If the consumer component that provided the input {@link android.view.Surface Surface} 94 * abandons the {@link android.view.Surface Surface}, {@link #queueInputImage queueing} 95 * or {@link #dequeueInputImage dequeueing} an {@link Image} will throw an 96 * {@link IllegalStateException}. 97 * </p> 98 */ 99 public class ImageWriter implements AutoCloseable { 100 private final Object mListenerLock = new Object(); 101 private OnImageReleasedListener mListener; 102 private ListenerHandler mListenerHandler; 103 private final Object mCloseLock = new Object(); 104 private boolean mIsWriterValid = false; 105 private long mNativeContext; 106 107 private int mWidth; 108 private int mHeight; 109 private final int mMaxImages; 110 private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; 111 private @HardwareBuffer.Format int mHardwareBufferFormat; 112 private @NamedDataSpace int mDataSpace; 113 114 // Field below is used by native code, do not access or modify. 115 private int mWriterFormat; 116 117 // Keep track of the currently dequeued Image. This need to be thread safe as the images 118 // could be closed by different threads (e.g., application thread and GC thread). 119 private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>(); 120 private int mEstimatedNativeAllocBytes; 121 122 /** 123 * <p> 124 * Create a new ImageWriter. 125 * </p> 126 * <p> 127 * The {@code maxImages} parameter determines the maximum number of 128 * {@link Image} objects that can be be dequeued from the 129 * {@code ImageWriter} simultaneously. Requesting more buffers will use up 130 * more memory, so it is important to use only the minimum number necessary. 131 * </p> 132 * <p> 133 * The input Image size and format depend on the Surface that is provided by 134 * the downstream consumer end-point. 135 * </p> 136 * 137 * @param surface The destination Surface this writer produces Image data 138 * into. 139 * @param maxImages The maximum number of Images the user will want to 140 * access simultaneously for producing Image data. This should be 141 * as small as possible to limit memory use. Once maxImages 142 * Images are dequeued by the user, one of them has to be queued 143 * back before a new Image can be dequeued for access via 144 * {@link #dequeueInputImage()}. 145 * @return a new ImageWriter instance. 146 */ newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages)147 public static @NonNull ImageWriter newInstance(@NonNull Surface surface, 148 @IntRange(from = 1) int maxImages) { 149 return new ImageWriter(surface, maxImages, true, ImageFormat.UNKNOWN, -1 /*width*/, 150 -1 /*height*/); 151 } 152 153 /** 154 * <p> 155 * Create a new ImageWriter with given number of max Images, format and producer dimension. 156 * </p> 157 * <p> 158 * The {@code maxImages} parameter determines the maximum number of 159 * {@link Image} objects that can be be dequeued from the 160 * {@code ImageWriter} simultaneously. Requesting more buffers will use up 161 * more memory, so it is important to use only the minimum number necessary. 162 * </p> 163 * <p> 164 * The format specifies the image format of this ImageWriter. The format 165 * from the {@code surface} will be overridden with this format. For example, 166 * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default 167 * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter 168 * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate 169 * with {@link ImageFormat#PRIVATE} Images. 170 * </p> 171 * <p> 172 * Note that the consumer end-point may or may not be able to support Images with different 173 * format, for such case, the application should only use this method if the consumer is able 174 * to consume such images. 175 * </p> 176 * <p> The input Image size can also be set by the client. </p> 177 * 178 * @param surface The destination Surface this writer produces Image data 179 * into. 180 * @param maxImages The maximum number of Images the user will want to 181 * access simultaneously for producing Image data. This should be 182 * as small as possible to limit memory use. Once maxImages 183 * Images are dequeued by the user, one of them has to be queued 184 * back before a new Image can be dequeued for access via 185 * {@link #dequeueInputImage()}. 186 * @param format The format of this ImageWriter. It can be any valid format specified by 187 * {@link ImageFormat} or {@link PixelFormat}. 188 * 189 * @param width Input size width. 190 * @param height Input size height. 191 * 192 * @return a new ImageWriter instance. 193 * 194 * @hide 195 */ newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format, int width, int height)196 public static @NonNull ImageWriter newInstance(@NonNull Surface surface, 197 @IntRange(from = 1) int maxImages, @Format int format, int width, int height) { 198 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { 199 throw new IllegalArgumentException("Invalid format is specified: " + format); 200 } 201 return new ImageWriter(surface, maxImages, false, format, width, height); 202 } 203 204 /** 205 * <p> 206 * Create a new ImageWriter with given number of max Images and format. 207 * </p> 208 * <p> 209 * The {@code maxImages} parameter determines the maximum number of 210 * {@link Image} objects that can be be dequeued from the 211 * {@code ImageWriter} simultaneously. Requesting more buffers will use up 212 * more memory, so it is important to use only the minimum number necessary. 213 * </p> 214 * <p> 215 * The format specifies the image format of this ImageWriter. The format 216 * from the {@code surface} will be overridden with this format. For example, 217 * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default 218 * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter 219 * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate 220 * with {@link ImageFormat#PRIVATE} Images. 221 * </p> 222 * <p> 223 * Note that the consumer end-point may or may not be able to support Images with different 224 * format, for such case, the application should only use this method if the consumer is able 225 * to consume such images. 226 * </p> 227 * <p> 228 * The input Image size depends on the Surface that is provided by 229 * the downstream consumer end-point. 230 * </p> 231 * 232 * @param surface The destination Surface this writer produces Image data 233 * into. 234 * @param maxImages The maximum number of Images the user will want to 235 * access simultaneously for producing Image data. This should be 236 * as small as possible to limit memory use. Once maxImages 237 * Images are dequeued by the user, one of them has to be queued 238 * back before a new Image can be dequeued for access via 239 * {@link #dequeueInputImage()}. 240 * @param format The format of this ImageWriter. It can be any valid format specified by 241 * {@link ImageFormat} or {@link PixelFormat}. 242 * 243 * @return a new ImageWriter instance. 244 */ newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format)245 public static @NonNull ImageWriter newInstance(@NonNull Surface surface, 246 @IntRange(from = 1) int maxImages, @Format int format) { 247 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { 248 throw new IllegalArgumentException("Invalid format is specified: " + format); 249 } 250 return new ImageWriter(surface, maxImages, false, format, -1 /*width*/, -1 /*height*/); 251 } 252 initializeImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat, int hardwareBufferFormat, int dataSpace, int width, int height, long usage)253 private void initializeImageWriter(Surface surface, int maxImages, 254 boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat, 255 int hardwareBufferFormat, int dataSpace, int width, int height, long usage) { 256 if (surface == null || maxImages < 1) { 257 throw new IllegalArgumentException("Illegal input argument: surface " + surface 258 + ", maxImages: " + maxImages); 259 } 260 261 // Note that the underlying BufferQueue is working in synchronous mode 262 // to avoid dropping any buffers. 263 mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height, 264 useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage); 265 266 // if useSurfaceImageFormatInfo is true, imageformat should be read from the surface. 267 if (useSurfaceImageFormatInfo) { 268 // nativeInit internally overrides UNKNOWN format. So does surface format query after 269 // nativeInit and before getEstimatedNativeAllocBytes(). 270 imageFormat = SurfaceUtils.getSurfaceFormat(surface); 271 mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); 272 mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); 273 } 274 275 // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native 276 // allocation estimation sequence depends on the public formats values. To avoid 277 // possible errors, convert where necessary. 278 if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) { 279 int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface); 280 switch (surfaceDataspace) { 281 case StreamConfigurationMap.HAL_DATASPACE_DEPTH: 282 imageFormat = ImageFormat.DEPTH_POINT_CLOUD; 283 break; 284 case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH: 285 imageFormat = ImageFormat.DEPTH_JPEG; 286 break; 287 case StreamConfigurationMap.HAL_DATASPACE_HEIF: 288 imageFormat = ImageFormat.HEIC; 289 break; 290 default: 291 imageFormat = ImageFormat.JPEG; 292 } 293 mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); 294 mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); 295 } 296 // Estimate the native buffer allocation size and register it so it gets accounted for 297 // during GC. Note that this doesn't include the buffers required by the buffer queue 298 // itself and the buffers requested by the producer. 299 // Only include memory for 1 buffer, since actually accounting for the memory used is 300 // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some 301 // size. 302 Size surfSize = SurfaceUtils.getSurfaceSize(surface); 303 mWidth = width == -1 ? surfSize.getWidth() : width; 304 mHeight = height == -1 ? surfSize.getHeight() : height; 305 306 mEstimatedNativeAllocBytes = 307 ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight, 308 useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1); 309 VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes); 310 311 mIsWriterValid = true; 312 } 313 ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height)314 private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, 315 int imageFormat, int width, int height) { 316 mMaxImages = maxImages; 317 mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); 318 mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); 319 320 initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true, 321 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage); 322 } 323 ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height, long usage)324 private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, 325 int imageFormat, int width, int height, long usage) { 326 mMaxImages = maxImages; 327 mUsage = usage; 328 mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); 329 mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); 330 331 initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true, 332 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage); 333 } 334 ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat, int dataSpace, int width, int height, long usage)335 private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, 336 int hardwareBufferFormat, int dataSpace, int width, int height, long usage) { 337 mMaxImages = maxImages; 338 mUsage = usage; 339 int imageFormat; 340 // if useSurfaceImageFormatInfo is true, imageFormat will be set to UNKNOWN 341 // and retrieve corresponding hardwareBufferFormat and dataSpace here. 342 if (useSurfaceImageFormatInfo) { 343 imageFormat = ImageFormat.UNKNOWN; 344 mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); 345 mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); 346 } else { 347 imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace); 348 mHardwareBufferFormat = hardwareBufferFormat; 349 mDataSpace = dataSpace; 350 } 351 352 initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false, 353 imageFormat, hardwareBufferFormat, dataSpace, width, height, usage); 354 } 355 356 /** 357 * <p> 358 * Maximum number of Images that can be dequeued from the ImageWriter 359 * simultaneously (for example, with {@link #dequeueInputImage()}). 360 * </p> 361 * <p> 362 * An Image is considered dequeued after it's returned by 363 * {@link #dequeueInputImage()} from ImageWriter, and until the Image is 364 * sent back to ImageWriter via {@link #queueInputImage}, or 365 * {@link Image#close()}. 366 * </p> 367 * <p> 368 * Attempting to dequeue more than {@code maxImages} concurrently will 369 * result in the {@link #dequeueInputImage()} function throwing an 370 * {@link IllegalStateException}. 371 * </p> 372 * 373 * @return Maximum number of Images that can be dequeued from this 374 * ImageWriter. 375 * @see #dequeueInputImage 376 * @see #queueInputImage 377 * @see Image#close 378 */ getMaxImages()379 public int getMaxImages() { 380 return mMaxImages; 381 } 382 383 /** 384 * The width of {@link Image Images}, in pixels. 385 * 386 * <p>If {@link Builder#setWidthAndHeight} is not called, the default width of the Image 387 * depends on the Surface provided by customer end-point.</p> 388 * 389 * @return the expected actual width of an Image. 390 */ getWidth()391 public int getWidth() { 392 return mWidth; 393 } 394 395 /** 396 * The height of {@link Image Images}, in pixels. 397 * 398 * <p>If {@link Builder#setWidthAndHeight} is not called, the default height of the Image 399 * depends on the Surface provided by customer end-point.</p> 400 * 401 * @return the expected height of an Image. 402 */ getHeight()403 public int getHeight() { 404 return mHeight; 405 } 406 407 /** 408 * <p> 409 * Dequeue the next available input Image for the application to produce 410 * data into. 411 * </p> 412 * <p> 413 * This method requests a new input Image from ImageWriter. The application 414 * owns this Image after this call. Once the application fills the Image 415 * data, it is expected to return this Image back to ImageWriter for 416 * downstream consumer components (e.g. 417 * {@link android.hardware.camera2.CameraDevice}) to consume. The Image can 418 * be returned to ImageWriter via {@link #queueInputImage} or 419 * {@link Image#close()}. 420 * </p> 421 * <p> 422 * This call will block if all available input images have been queued by 423 * the application and the downstream consumer has not yet consumed any. 424 * When an Image is consumed by the downstream consumer and released, an 425 * {@link OnImageReleasedListener#onImageReleased} callback will be fired, 426 * which indicates that there is one input Image available. For non- 427 * {@link ImageFormat#PRIVATE PRIVATE} formats ( 428 * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is 429 * recommended to dequeue the next Image only after this callback is fired, 430 * in the steady state. 431 * </p> 432 * <p> 433 * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} ( 434 * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the 435 * image buffer is accessible to the application only through the hardware 436 * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android 437 * versions prior to P, dequeueing private buffers will cause an 438 * {@link IllegalStateException} to be thrown). Alternatively, 439 * the application can acquire images from some other component (e.g. an 440 * {@link ImageReader}), and queue them directly to this ImageWriter via the 441 * {@link ImageWriter#queueInputImage queueInputImage()} method. 442 * </p> 443 * 444 * @return The next available input Image from this ImageWriter. 445 * @throws IllegalStateException if {@code maxImages} Images are currently 446 * dequeued, or the input {@link android.view.Surface Surface} 447 * has been abandoned by the consumer component that provided 448 * the {@link android.view.Surface Surface}. Prior to Android 449 * P, throws if the ImageWriter format is 450 * {@link ImageFormat#PRIVATE PRIVATE}. 451 * @see #queueInputImage 452 * @see Image#close 453 */ dequeueInputImage()454 public Image dequeueInputImage() { 455 if (mDequeuedImages.size() >= mMaxImages) { 456 throw new IllegalStateException( 457 "Already dequeued max number of Images " + mMaxImages); 458 } 459 WriterSurfaceImage newImage = new WriterSurfaceImage(this); 460 nativeDequeueInputImage(mNativeContext, newImage); 461 mDequeuedImages.add(newImage); 462 newImage.mIsImageValid = true; 463 return newImage; 464 } 465 466 /** 467 * <p> 468 * Queue an input {@link Image} back to ImageWriter for the downstream 469 * consumer to access. 470 * </p> 471 * <p> 472 * The input {@link Image} could be from ImageReader (acquired via 473 * {@link ImageReader#acquireNextImage} or 474 * {@link ImageReader#acquireLatestImage}), or from this ImageWriter 475 * (acquired via {@link #dequeueInputImage}). In the former case, the Image 476 * data will be moved to this ImageWriter. Note that the Image properties 477 * (size, format, strides, etc.) must be the same as the properties of the 478 * images dequeued from this ImageWriter. In the latter case, the application has 479 * filled the input image with data. This method then passes the filled 480 * buffer to the downstream consumer. In both cases, it's up to the caller 481 * to ensure that the Image timestamp (in nanoseconds) is correctly set, as 482 * the downstream component may want to use it to indicate the Image data 483 * capture time. 484 * </p> 485 * <p> 486 * After this method is called and the downstream consumer consumes and 487 * releases the Image, an {@link OnImageReleasedListener#onImageReleased} 488 * callback will fire. The application can use this callback to avoid 489 * sending Images faster than the downstream consumer processing rate in 490 * steady state. 491 * </p> 492 * <p> 493 * Passing in an Image from some other component (e.g. an 494 * {@link ImageReader}) requires a free input Image from this ImageWriter as 495 * the destination. In this case, this call will block, as 496 * {@link #dequeueInputImage} does, if there are no free Images available. 497 * To avoid blocking, the application should ensure that there is at least 498 * one free Image available in this ImageWriter before calling this method. 499 * </p> 500 * <p> 501 * After this call, the input Image is no longer valid for further access, 502 * as if the Image is {@link Image#close closed}. Attempting to access the 503 * {@link ByteBuffer ByteBuffers} returned by an earlier 504 * {@link Image.Plane#getBuffer Plane#getBuffer} call will result in an 505 * {@link IllegalStateException}. 506 * </p> 507 * 508 * @param image The Image to be queued back to ImageWriter for future 509 * consumption. 510 * @throws IllegalStateException if the image was already queued previously, 511 * or the image was aborted previously, or the input 512 * {@link android.view.Surface Surface} has been abandoned by the 513 * consumer component that provided the 514 * {@link android.view.Surface Surface}. 515 * @see #dequeueInputImage() 516 */ queueInputImage(Image image)517 public void queueInputImage(Image image) { 518 if (image == null) { 519 throw new IllegalArgumentException("image shouldn't be null"); 520 } 521 522 boolean ownedByMe = isImageOwnedByMe(image); 523 if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) { 524 throw new IllegalStateException("Image from ImageWriter is invalid"); 525 } 526 527 // For images from other components that have non-null owner, need to detach first, 528 // then attach. Images without owners must already be attachable. 529 if (!ownedByMe) { 530 if ((image.getOwner() instanceof ImageReader)) { 531 ImageReader prevOwner = (ImageReader) image.getOwner(); 532 533 prevOwner.detachImage(image); 534 } else if (image.getOwner() != null) { 535 throw new IllegalArgumentException( 536 "Only images from ImageReader can be queued to" 537 + " ImageWriter, other image source is not supported yet!"); 538 } 539 540 attachAndQueueInputImage(image); 541 // This clears the native reference held by the original owner. 542 // When this Image is detached later by this ImageWriter, the 543 // native memory won't be leaked. 544 image.close(); 545 return; 546 } 547 548 Rect crop = image.getCropRect(); 549 nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), image.getDataSpace(), 550 crop.left, crop.top, crop.right, crop.bottom, image.getTransform(), 551 image.getScalingMode()); 552 553 /** 554 * Only remove and cleanup the Images that are owned by this 555 * ImageWriter. Images detached from other owners are only temporarily 556 * owned by this ImageWriter and will be detached immediately after they 557 * are released by downstream consumers, so there is no need to keep 558 * track of them in mDequeuedImages. 559 */ 560 if (ownedByMe) { 561 mDequeuedImages.remove(image); 562 // Do not call close here, as close is essentially cancel image. 563 WriterSurfaceImage wi = (WriterSurfaceImage) image; 564 wi.clearSurfacePlanes(); 565 wi.mIsImageValid = false; 566 } 567 } 568 569 /** 570 * Get the ImageWriter format. 571 * <p> 572 * This format may be different than the Image format returned by 573 * {@link Image#getFormat()}. However, if the ImageWriter format is 574 * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()} 575 * will result in an {@link IllegalStateException}. 576 * </p> 577 * 578 * @return The ImageWriter format. 579 */ getFormat()580 public int getFormat() { 581 return mWriterFormat; 582 } 583 584 /** 585 * Get the ImageWriter usage flag. 586 * 587 * <p>It is not recommended to use this function if {@link Builder#setUsage} is not called. 588 * Invalid usage value will be returned if so.</p> 589 * 590 * @return The ImageWriter usage flag. 591 */ getUsage()592 public @Usage long getUsage() { 593 return mUsage; 594 } 595 596 /** 597 * Get the ImageWriter hardwareBuffer format. 598 * 599 * <p>Use this function if the ImageWriter instance is created by builder pattern 600 * {@code ImageWriter.Builder} and using {@link Builder#setHardwareBufferFormat} and 601 * {@link Builder#setDataSpace}.</p> 602 * 603 * @return The ImageWriter hardwareBuffer format. 604 */ getHardwareBufferFormat()605 public @HardwareBuffer.Format int getHardwareBufferFormat() { 606 return mHardwareBufferFormat; 607 } 608 609 /** 610 * Get the ImageWriter dataspace. 611 * 612 * <p>Use this function if the ImageWriter instance is created by builder pattern 613 * {@code ImageWriter.Builder} and {@link Builder#setDataSpace}.</p> 614 * 615 * @return The ImageWriter dataspace. 616 */ 617 @SuppressLint("MethodNameUnits") getDataSpace()618 public @NamedDataSpace int getDataSpace() { 619 return mDataSpace; 620 } 621 622 /** 623 * ImageWriter callback interface, used to to asynchronously notify the 624 * application of various ImageWriter events. 625 */ 626 public interface OnImageReleasedListener { 627 /** 628 * <p> 629 * Callback that is called when an input Image is released back to 630 * ImageWriter after the data consumption. 631 * </p> 632 * <p> 633 * The client can use this callback to be notified that an input Image 634 * has been consumed and released by the downstream consumer. More 635 * specifically, this callback will be fired for below cases: 636 * <li>The application dequeues an input Image via the 637 * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method, 638 * uses it, and then queues it back to this ImageWriter via the 639 * {@link ImageWriter#queueInputImage queueInputImage()} method. After 640 * the downstream consumer uses and releases this image to this 641 * ImageWriter, this callback will be fired. This image will be 642 * available to be dequeued after this callback.</li> 643 * <li>The application obtains an Image from some other component (e.g. 644 * an {@link ImageReader}), uses it, and then queues it to this 645 * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}. 646 * After the downstream consumer uses and releases this image to this 647 * ImageWriter, this callback will be fired.</li> 648 * </p> 649 * 650 * @param writer the ImageWriter the callback is associated with. 651 * @see ImageWriter 652 * @see Image 653 */ onImageReleased(ImageWriter writer)654 void onImageReleased(ImageWriter writer); 655 } 656 657 /** 658 * Register a listener to be invoked when an input Image is returned to the 659 * ImageWriter. 660 * 661 * @param listener The listener that will be run. 662 * @param handler The handler on which the listener should be invoked, or 663 * null if the listener should be invoked on the calling thread's 664 * looper. 665 * @throws IllegalArgumentException If no handler specified and the calling 666 * thread has no looper. 667 */ setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler)668 public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) { 669 synchronized (mListenerLock) { 670 if (listener != null) { 671 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); 672 if (looper == null) { 673 throw new IllegalArgumentException( 674 "handler is null but the current thread is not a looper"); 675 } 676 if (mListenerHandler == null || mListenerHandler.getLooper() != looper) { 677 mListenerHandler = new ListenerHandler(looper); 678 } 679 mListener = listener; 680 } else { 681 mListener = null; 682 mListenerHandler = null; 683 } 684 } 685 } 686 687 /** 688 * Free up all the resources associated with this ImageWriter. 689 * <p> 690 * After calling this method, this ImageWriter cannot be used. Calling any 691 * methods on this ImageWriter and Images previously provided by 692 * {@link #dequeueInputImage()} will result in an 693 * {@link IllegalStateException}, and attempting to write into 694 * {@link ByteBuffer ByteBuffers} returned by an earlier 695 * {@link Image.Plane#getBuffer Plane#getBuffer} call will have undefined 696 * behavior. 697 * </p> 698 */ 699 @Override close()700 public void close() { 701 setOnImageReleasedListener(null, null); 702 synchronized (mCloseLock) { 703 if (!mIsWriterValid) { 704 return; 705 } 706 for (Image image : mDequeuedImages) { 707 image.close(); 708 } 709 mDequeuedImages.clear(); 710 nativeClose(mNativeContext); 711 mNativeContext = 0; 712 713 if (mEstimatedNativeAllocBytes > 0) { 714 VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes); 715 mEstimatedNativeAllocBytes = 0; 716 } 717 mIsWriterValid = false; 718 } 719 } 720 721 @Override finalize()722 protected void finalize() throws Throwable { 723 try { 724 close(); 725 } finally { 726 super.finalize(); 727 } 728 } 729 730 /** 731 * <p> 732 * Attach and queue input Image to this ImageWriter. 733 * </p> 734 * <p> 735 * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or 736 * the source Image is so large that copying its data is too expensive, this 737 * method can be used to migrate the source Image into ImageWriter without a 738 * data copy, and then queue it to this ImageWriter. The source Image must 739 * be detached from its previous owner already, or this call will throw an 740 * {@link IllegalStateException}. 741 * </p> 742 * <p> 743 * After this call, the ImageWriter takes ownership of this Image. This 744 * ownership will automatically be removed from this writer after the 745 * consumer releases this Image, that is, after 746 * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for 747 * closing this Image through {@link Image#close()} to free up the resources 748 * held by this Image. 749 * </p> 750 * 751 * @param image The source Image to be attached and queued into this 752 * ImageWriter for downstream consumer to use. 753 * @throws IllegalStateException if the Image is not detached from its 754 * previous owner, or the Image is already attached to this 755 * ImageWriter, or the source Image is invalid. 756 */ attachAndQueueInputImage(Image image)757 private void attachAndQueueInputImage(Image image) { 758 if (image == null) { 759 throw new IllegalArgumentException("image shouldn't be null"); 760 } 761 if (isImageOwnedByMe(image)) { 762 throw new IllegalArgumentException( 763 "Can not attach an image that is owned ImageWriter already"); 764 } 765 /** 766 * Throw ISE if the image is not attachable, which means that it is 767 * either owned by other entity now, or completely non-attachable (some 768 * stand-alone images are not backed by native gralloc buffer, thus not 769 * attachable). 770 */ 771 if (!image.isAttachable()) { 772 throw new IllegalStateException("Image was not detached from last owner, or image " 773 + " is not detachable"); 774 } 775 776 // TODO: what if attach failed, throw RTE or detach a slot then attach? 777 // need do some cleanup to make sure no orphaned 778 // buffer caused leak. 779 Rect crop = image.getCropRect(); 780 if (image.getNativeContext() != 0) { 781 nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(), 782 image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right, 783 crop.bottom, image.getTransform(), image.getScalingMode()); 784 } else { 785 GraphicBuffer gb = GraphicBuffer.createFromHardwareBuffer(image.getHardwareBuffer()); 786 nativeAttachAndQueueGraphicBuffer(mNativeContext, gb, image.getFormat(), 787 image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right, 788 crop.bottom, image.getTransform(), image.getScalingMode()); 789 gb.destroy(); 790 image.close(); 791 } 792 } 793 794 /** 795 * This custom handler runs asynchronously so callbacks don't get queued 796 * behind UI messages. 797 */ 798 private final class ListenerHandler extends Handler { ListenerHandler(Looper looper)799 public ListenerHandler(Looper looper) { 800 super(looper, null, true /* async */); 801 } 802 803 @Override handleMessage(Message msg)804 public void handleMessage(Message msg) { 805 OnImageReleasedListener listener; 806 boolean isWriterValid; 807 synchronized (ImageWriter.this.mListenerLock) { 808 listener = mListener; 809 } 810 // Check to make sure we don't accidentally queue images after the writer is 811 // closed or closing 812 synchronized (ImageWriter.this.mCloseLock) { 813 isWriterValid = ImageWriter.this.mIsWriterValid; 814 } 815 if (listener != null && isWriterValid) { 816 listener.onImageReleased(ImageWriter.this); 817 } 818 } 819 } 820 821 /** 822 * Called from Native code when an Event happens. This may be called from an 823 * arbitrary Binder thread, so access to the ImageWriter must be 824 * synchronized appropriately. 825 */ postEventFromNative(Object selfRef)826 private static void postEventFromNative(Object selfRef) { 827 @SuppressWarnings("unchecked") 828 WeakReference<ImageWriter> weakSelf = (WeakReference<ImageWriter>) selfRef; 829 final ImageWriter iw = weakSelf.get(); 830 if (iw == null) { 831 return; 832 } 833 834 final Handler handler; 835 synchronized (iw.mListenerLock) { 836 handler = iw.mListenerHandler; 837 } 838 839 if (handler != null) { 840 // The ListenerHandler will take care of ensuring that the parent ImageWriter is valid 841 handler.sendEmptyMessage(0); 842 } 843 } 844 845 /** 846 * <p> 847 * Abort the Images that were dequeued from this ImageWriter, and return 848 * them to this writer for reuse. 849 * </p> 850 * <p> 851 * This method is used for the cases where the application dequeued the 852 * Image, may have filled the data, but does not want the downstream 853 * component to consume it. The Image will be returned to this ImageWriter 854 * for reuse after this call, and the ImageWriter will immediately have an 855 * Image available to be dequeued. This aborted Image will be invisible to 856 * the downstream consumer, as if nothing happened. 857 * </p> 858 * 859 * @param image The Image to be aborted. 860 * @see #dequeueInputImage() 861 * @see Image#close() 862 */ abortImage(Image image)863 private void abortImage(Image image) { 864 if (image == null) { 865 throw new IllegalArgumentException("image shouldn't be null"); 866 } 867 868 if (!mDequeuedImages.contains(image)) { 869 throw new IllegalStateException("It is illegal to abort some image that is not" 870 + " dequeued yet"); 871 } 872 873 WriterSurfaceImage wi = (WriterSurfaceImage) image; 874 if (!wi.mIsImageValid) { 875 return; 876 } 877 878 /** 879 * We only need abort Images that are owned and dequeued by ImageWriter. 880 * For attached Images, no need to abort, as there are only two cases: 881 * attached + queued successfully, and attach failed. Neither of the 882 * cases need abort. 883 */ 884 cancelImage(mNativeContext, image); 885 mDequeuedImages.remove(image); 886 wi.clearSurfacePlanes(); 887 wi.mIsImageValid = false; 888 } 889 isImageOwnedByMe(Image image)890 private boolean isImageOwnedByMe(Image image) { 891 if (!(image instanceof WriterSurfaceImage)) { 892 return false; 893 } 894 WriterSurfaceImage wi = (WriterSurfaceImage) image; 895 if (wi.getOwner() != this) { 896 return false; 897 } 898 899 return true; 900 } 901 902 /** 903 * Builder class for {@link ImageWriter} objects. 904 */ 905 public static final class Builder { 906 private Surface mSurface; 907 private int mWidth = -1; 908 private int mHeight = -1; 909 private int mMaxImages = 1; 910 private int mImageFormat = ImageFormat.UNKNOWN; 911 private long mUsage = -1; 912 private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888; 913 private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN; 914 private boolean mUseSurfaceImageFormatInfo = true; 915 private boolean mUseLegacyImageFormat = false; 916 917 /** 918 * Constructs a new builder for {@link ImageWriter}. 919 * 920 * @param surface The destination Surface this writer produces Image data into. 921 * 922 * @throws IllegalArgumentException if the surface is already abandoned. 923 */ Builder(@onNull Surface surface)924 public Builder(@NonNull Surface surface) { 925 mSurface = surface; 926 } 927 928 /** 929 * Set the width and height of images. Default size is dependent on the Surface that is 930 * provided by the downstream end-point. 931 * 932 * @param width The width in pixels that will be passed to the producer. 933 * @param height The height in pixels that will be passed to the producer. 934 * @return the Builder instance with customized width and height. 935 */ 936 @SuppressLint("MissingGetterMatchingBuilder") setWidthAndHeight(@ntRangefrom = 1) int width, @IntRange(from = 1) int height)937 public @NonNull Builder setWidthAndHeight(@IntRange(from = 1) int width, 938 @IntRange(from = 1) int height) { 939 mWidth = width; 940 mHeight = height; 941 return this; 942 } 943 944 /** 945 * Set the maximum number of images. Default value is 1. 946 * 947 * @param maxImages The maximum number of Images the user will want to access simultaneously 948 * for producing Image data. 949 * @return the Builder instance with customized usage value. 950 */ setMaxImages(@ntRangefrom = 1) int maxImages)951 public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) { 952 mMaxImages = maxImages; 953 return this; 954 } 955 956 /** 957 * Set the image format of this ImageWriter. 958 * Default format depends on the Surface provided. 959 * 960 * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified 961 * by {@link ImageFormat} or {@link PixelFormat}. 962 * @return the Builder instance with customized image format. 963 * 964 * @throws IllegalArgumentException if {@code imageFormat} is invalid. 965 */ 966 @SuppressLint("MissingGetterMatchingBuilder") setImageFormat(@ormat int imageFormat)967 public @NonNull Builder setImageFormat(@Format int imageFormat) { 968 if (!ImageFormat.isPublicFormat(imageFormat) 969 && !PixelFormat.isPublicFormat(imageFormat)) { 970 throw new IllegalArgumentException( 971 "Invalid imageFormat is specified: " + imageFormat); 972 } 973 mImageFormat = imageFormat; 974 mUseLegacyImageFormat = true; 975 mHardwareBufferFormat = HardwareBuffer.RGBA_8888; 976 mDataSpace = DataSpace.DATASPACE_UNKNOWN; 977 mUseSurfaceImageFormatInfo = false; 978 return this; 979 } 980 981 /** 982 * Set the hardwareBuffer format of this ImageWriter. The default value is 983 * {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}. 984 * 985 * <p>This function works together with {@link #setDataSpace} for an 986 * {@link ImageWriter} instance. Setting at least one of these two replaces 987 * {@link #setImageFormat} function.</p> 988 * 989 * @param hardwareBufferFormat The HardwareBuffer format of the image that this writer 990 * will produce. 991 * @return the Builder instance with customized buffer format. 992 * 993 * @see #setDataSpace 994 * @see #setImageFormat 995 */ setHardwareBufferFormat( @ardwareBuffer.Format int hardwareBufferFormat)996 public @NonNull Builder setHardwareBufferFormat( 997 @HardwareBuffer.Format int hardwareBufferFormat) { 998 mHardwareBufferFormat = hardwareBufferFormat; 999 mImageFormat = ImageFormat.UNKNOWN; 1000 mUseLegacyImageFormat = false; 1001 mUseSurfaceImageFormatInfo = false; 1002 return this; 1003 } 1004 1005 /** 1006 * Set the dataspace of this ImageWriter. 1007 * The default value is {@link DataSpace#DATASPACE_UNKNOWN}. 1008 * 1009 * @param dataSpace The dataspace of the image that this writer will produce. 1010 * @return the builder instance with customized dataspace value. 1011 * 1012 * @see #setHardwareBufferFormat 1013 */ setDataSpace(@amedDataSpace int dataSpace)1014 public @NonNull Builder setDataSpace(@NamedDataSpace int dataSpace) { 1015 mDataSpace = dataSpace; 1016 mImageFormat = ImageFormat.UNKNOWN; 1017 mUseLegacyImageFormat = false; 1018 mUseSurfaceImageFormatInfo = false; 1019 return this; 1020 } 1021 1022 /** 1023 * Set the usage flag of this ImageWriter. 1024 * 1025 * <p>If this function is not called, usage bit will be set 1026 * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not 1027 * {@link ImageFormat#PRIVATE PRIVATE}.</p> 1028 * 1029 * @param usage The intended usage of the images produced by this ImageWriter. 1030 * @return the Builder instance with customized usage flag. 1031 * 1032 * @see HardwareBuffer 1033 * @see #getUsage 1034 */ setUsage(@sage long usage)1035 public @NonNull Builder setUsage(@Usage long usage) { 1036 mUsage = usage; 1037 return this; 1038 } 1039 1040 /** 1041 * Builds a new ImageWriter object. 1042 * 1043 * @return The new ImageWriter object. 1044 */ build()1045 public @NonNull ImageWriter build() { 1046 if (mUseLegacyImageFormat) { 1047 return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo, 1048 mImageFormat, mWidth, mHeight, mUsage); 1049 } else { 1050 return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo, 1051 mHardwareBufferFormat, mDataSpace, mWidth, mHeight, mUsage); 1052 } 1053 } 1054 } 1055 1056 private static class WriterSurfaceImage extends android.media.Image { 1057 private ImageWriter mOwner; 1058 // This field is used by native code, do not access or modify. 1059 private long mNativeBuffer; 1060 private int mNativeFenceFd = -1; 1061 private SurfacePlane[] mPlanes; 1062 private int mHeight = -1; 1063 private int mWidth = -1; 1064 private int mFormat = -1; 1065 private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN; 1066 // When this default timestamp is used, timestamp for the input Image 1067 // will be generated automatically when queueInputBuffer is called. 1068 private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE; 1069 private long mTimestamp = DEFAULT_TIMESTAMP; 1070 1071 private int mTransform = 0; //Default no transform 1072 private int mScalingMode = 0; //Default frozen scaling mode 1073 1074 private final Object mCloseLock = new Object(); // lock to protect against multiple 1075 // simultaneous calls to close() 1076 WriterSurfaceImage(ImageWriter writer)1077 public WriterSurfaceImage(ImageWriter writer) { 1078 mOwner = writer; 1079 mWidth = writer.mWidth; 1080 mHeight = writer.mHeight; 1081 mDataSpace = writer.mDataSpace; 1082 } 1083 1084 @Override getDataSpace()1085 public @NamedDataSpace int getDataSpace() { 1086 throwISEIfImageIsInvalid(); 1087 1088 return mDataSpace; 1089 } 1090 1091 @Override setDataSpace(@amedDataSpace int dataSpace)1092 public void setDataSpace(@NamedDataSpace int dataSpace) { 1093 throwISEIfImageIsInvalid(); 1094 1095 mDataSpace = dataSpace; 1096 } 1097 1098 @Override getFormat()1099 public int getFormat() { 1100 throwISEIfImageIsInvalid(); 1101 1102 if (mFormat == -1) { 1103 mFormat = nativeGetFormat(mDataSpace); 1104 } 1105 return mFormat; 1106 } 1107 1108 @Override getWidth()1109 public int getWidth() { 1110 throwISEIfImageIsInvalid(); 1111 1112 if (mWidth == -1) { 1113 mWidth = nativeGetWidth(); 1114 } 1115 1116 return mWidth; 1117 } 1118 1119 @Override getHeight()1120 public int getHeight() { 1121 throwISEIfImageIsInvalid(); 1122 1123 if (mHeight == -1) { 1124 mHeight = nativeGetHeight(); 1125 } 1126 1127 return mHeight; 1128 } 1129 1130 @Override getTransform()1131 public int getTransform() { 1132 throwISEIfImageIsInvalid(); 1133 1134 return mTransform; 1135 } 1136 1137 @Override getScalingMode()1138 public int getScalingMode() { 1139 throwISEIfImageIsInvalid(); 1140 1141 return mScalingMode; 1142 } 1143 1144 @Override getTimestamp()1145 public long getTimestamp() { 1146 throwISEIfImageIsInvalid(); 1147 1148 return mTimestamp; 1149 } 1150 1151 @Override setTimestamp(long timestamp)1152 public void setTimestamp(long timestamp) { 1153 throwISEIfImageIsInvalid(); 1154 1155 mTimestamp = timestamp; 1156 } 1157 1158 @Override getHardwareBuffer()1159 public HardwareBuffer getHardwareBuffer() { 1160 throwISEIfImageIsInvalid(); 1161 1162 return nativeGetHardwareBuffer(); 1163 } 1164 1165 @Override getFence()1166 public SyncFence getFence() throws IOException { 1167 throwISEIfImageIsInvalid(); 1168 // if mNativeFenceFd is -1, the fence is closed 1169 if (mNativeFenceFd != -1) { 1170 return SyncFence.create(ParcelFileDescriptor.fromFd(mNativeFenceFd)); 1171 } else { 1172 return SyncFence.createEmpty(); 1173 } 1174 } 1175 1176 @Override setFence(@onNull SyncFence fence)1177 public void setFence(@NonNull SyncFence fence) throws IOException { 1178 throwISEIfImageIsInvalid(); 1179 nativeSetFenceFd(fence.getFdDup().detachFd()); 1180 } 1181 1182 @Override getPlanes()1183 public Plane[] getPlanes() { 1184 throwISEIfImageIsInvalid(); 1185 1186 if (mPlanes == null) { 1187 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat()); 1188 mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(), 1189 getOwner().getDataSpace()); 1190 } 1191 1192 return mPlanes.clone(); 1193 } 1194 1195 @Override isAttachable()1196 public boolean isAttachable() { 1197 throwISEIfImageIsInvalid(); 1198 // Don't allow Image to be detached from ImageWriter for now, as no 1199 // detach API is exposed. 1200 return false; 1201 } 1202 1203 @Override getOwner()1204 ImageWriter getOwner() { 1205 throwISEIfImageIsInvalid(); 1206 1207 return mOwner; 1208 } 1209 1210 @Override getNativeContext()1211 long getNativeContext() { 1212 throwISEIfImageIsInvalid(); 1213 1214 return mNativeBuffer; 1215 } 1216 1217 @Override close()1218 public void close() { 1219 synchronized (mCloseLock) { 1220 if (mIsImageValid) { 1221 getOwner().abortImage(this); 1222 } 1223 } 1224 } 1225 1226 @Override finalize()1227 protected final void finalize() throws Throwable { 1228 try { 1229 close(); 1230 } finally { 1231 super.finalize(); 1232 } 1233 } 1234 clearSurfacePlanes()1235 private void clearSurfacePlanes() { 1236 if (mIsImageValid && mPlanes != null) { 1237 for (int i = 0; i < mPlanes.length; i++) { 1238 if (mPlanes[i] != null) { 1239 mPlanes[i].clearBuffer(); 1240 mPlanes[i] = null; 1241 } 1242 } 1243 } 1244 } 1245 1246 private class SurfacePlane extends android.media.Image.Plane { 1247 private ByteBuffer mBuffer; 1248 final private int mPixelStride; 1249 final private int mRowStride; 1250 1251 // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is 1252 // called SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer)1253 private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) { 1254 mRowStride = rowStride; 1255 mPixelStride = pixelStride; 1256 mBuffer = buffer; 1257 /** 1258 * Set the byteBuffer order according to host endianness (native 1259 * order), otherwise, the byteBuffer order defaults to 1260 * ByteOrder.BIG_ENDIAN. 1261 */ 1262 mBuffer.order(ByteOrder.nativeOrder()); 1263 } 1264 1265 @Override getRowStride()1266 public int getRowStride() { 1267 throwISEIfImageIsInvalid(); 1268 return mRowStride; 1269 } 1270 1271 @Override getPixelStride()1272 public int getPixelStride() { 1273 throwISEIfImageIsInvalid(); 1274 return mPixelStride; 1275 } 1276 1277 @Override getBuffer()1278 public ByteBuffer getBuffer() { 1279 throwISEIfImageIsInvalid(); 1280 return mBuffer; 1281 } 1282 clearBuffer()1283 private void clearBuffer() { 1284 // Need null check first, as the getBuffer() may not be called 1285 // before an Image is closed. 1286 if (mBuffer == null) { 1287 return; 1288 } 1289 1290 if (mBuffer.isDirect()) { 1291 NioUtils.freeDirectBuffer(mBuffer); 1292 } 1293 mBuffer = null; 1294 } 1295 1296 } 1297 1298 // Create the SurfacePlane object and fill the information nativeCreatePlanes(int numPlanes, int writerFmt, int dataSpace)1299 private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt, 1300 int dataSpace); 1301 nativeGetWidth()1302 private synchronized native int nativeGetWidth(); 1303 nativeGetHeight()1304 private synchronized native int nativeGetHeight(); 1305 nativeGetFormat(int dataSpace)1306 private synchronized native int nativeGetFormat(int dataSpace); 1307 nativeGetHardwareBuffer()1308 private synchronized native HardwareBuffer nativeGetHardwareBuffer(); 1309 nativeSetFenceFd(int fenceFd)1310 private synchronized native void nativeSetFenceFd(int fenceFd); 1311 } 1312 1313 // Native implemented ImageWriter methods. nativeInit(Object weakSelf, Surface surface, int maxImages, int width, int height, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat, int dataSpace, long usage)1314 private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImages, 1315 int width, int height, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat, 1316 int dataSpace, long usage); 1317 nativeClose(long nativeCtx)1318 private synchronized native void nativeClose(long nativeCtx); 1319 nativeDequeueInputImage(long nativeCtx, Image wi)1320 private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi); 1321 nativeQueueInputImage(long nativeCtx, Image image, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1322 private synchronized native void nativeQueueInputImage(long nativeCtx, Image image, 1323 long timestampNs, int dataSpace, int left, int top, int right, int bottom, 1324 int transform, int scalingMode); 1325 nativeAttachAndQueueImage(long nativeCtx, long imageNativeBuffer, int imageFormat, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1326 private synchronized native int nativeAttachAndQueueImage(long nativeCtx, 1327 long imageNativeBuffer, int imageFormat, long timestampNs, int dataSpace, 1328 int left, int top, int right, int bottom, int transform, int scalingMode); nativeAttachAndQueueGraphicBuffer(long nativeCtx, GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1329 private synchronized native int nativeAttachAndQueueGraphicBuffer(long nativeCtx, 1330 GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int dataSpace, 1331 int left, int top, int right, int bottom, int transform, int scalingMode); 1332 cancelImage(long nativeCtx, Image image)1333 private synchronized native void cancelImage(long nativeCtx, Image image); 1334 1335 /** 1336 * We use a class initializer to allow the native code to cache some field 1337 * offsets. 1338 */ nativeClassInit()1339 private static native void nativeClassInit(); 1340 1341 static { 1342 System.loadLibrary("media_jni"); nativeClassInit()1343 nativeClassInit(); 1344 } 1345 } 1346