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