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.graphics.ImageFormat; 22 import android.graphics.ImageFormat.Format; 23 import android.graphics.PixelFormat; 24 import android.graphics.Rect; 25 import android.hardware.camera2.utils.SurfaceUtils; 26 import android.hardware.HardwareBuffer; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.os.Message; 30 import android.util.Size; 31 import android.view.Surface; 32 33 import dalvik.system.VMRuntime; 34 35 import java.lang.ref.WeakReference; 36 import java.nio.ByteBuffer; 37 import java.nio.ByteOrder; 38 import java.nio.NioUtils; 39 import java.util.List; 40 import java.util.concurrent.CopyOnWriteArrayList; 41 42 /** 43 * <p> 44 * The ImageWriter class allows an application to produce Image data into a 45 * {@link android.view.Surface}, and have it be consumed by another component 46 * like {@link android.hardware.camera2.CameraDevice CameraDevice}. 47 * </p> 48 * <p> 49 * Several Android API classes can provide input {@link android.view.Surface 50 * Surface} objects for ImageWriter to produce data into, including 51 * {@link MediaCodec MediaCodec} (encoder), 52 * {@link android.hardware.camera2.CameraCaptureSession CameraCaptureSession} 53 * (reprocessing input), {@link ImageReader}, etc. 54 * </p> 55 * <p> 56 * The input Image data is encapsulated in {@link Image} objects. To produce 57 * Image data into a destination {@link android.view.Surface Surface}, the 58 * application can get an input Image via {@link #dequeueInputImage} then write 59 * Image data into it. Multiple such {@link Image} objects can be dequeued at 60 * the same time and queued back in any order, up to the number specified by the 61 * {@code maxImages} constructor parameter. 62 * </p> 63 * <p> 64 * If the application already has an Image from {@link ImageReader}, the 65 * application can directly queue this Image into the ImageWriter (via 66 * {@link #queueInputImage}), potentially with zero buffer copies. This 67 * even works if the image format of the ImageWriter is 68 * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only 69 * way to enqueue images into such an ImageWriter. Starting in Android P 70 * private images may also be accessed through their hardware buffers 71 * (when available) through the {@link Image#getHardwareBuffer()} method. 72 * Attempting to access the planes of a private image, will return an 73 * empty array. 74 * </p> 75 * <p> 76 * Once new input Images are queued into an ImageWriter, it's up to the 77 * downstream components (e.g. {@link ImageReader} or 78 * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the 79 * downstream components cannot consume the Images at least as fast as the 80 * ImageWriter production rate, the {@link #dequeueInputImage} call will 81 * eventually block and the application will have to drop input frames. 82 * </p> 83 * <p> 84 * If the consumer component that provided the input {@link android.view.Surface Surface} 85 * abandons the {@link android.view.Surface Surface}, {@link #queueInputImage queueing} 86 * or {@link #dequeueInputImage dequeueing} an {@link Image} will throw an 87 * {@link IllegalStateException}. 88 * </p> 89 */ 90 public class ImageWriter implements AutoCloseable { 91 private final Object mListenerLock = new Object(); 92 private OnImageReleasedListener mListener; 93 private ListenerHandler mListenerHandler; 94 private long mNativeContext; 95 96 // Field below is used by native code, do not access or modify. 97 private int mWriterFormat; 98 99 private final int mMaxImages; 100 // Keep track of the currently dequeued Image. This need to be thread safe as the images 101 // could be closed by different threads (e.g., application thread and GC thread). 102 private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>(); 103 private int mEstimatedNativeAllocBytes; 104 105 /** 106 * <p> 107 * Create a new ImageWriter. 108 * </p> 109 * <p> 110 * The {@code maxImages} parameter determines the maximum number of 111 * {@link Image} objects that can be be dequeued from the 112 * {@code ImageWriter} simultaneously. Requesting more buffers will use up 113 * more memory, so it is important to use only the minimum number necessary. 114 * </p> 115 * <p> 116 * The input Image size and format depend on the Surface that is provided by 117 * the downstream consumer end-point. 118 * </p> 119 * 120 * @param surface The destination Surface this writer produces Image data 121 * into. 122 * @param maxImages The maximum number of Images the user will want to 123 * access simultaneously for producing Image data. This should be 124 * as small as possible to limit memory use. Once maxImages 125 * Images are dequeued by the user, one of them has to be queued 126 * back before a new Image can be dequeued for access via 127 * {@link #dequeueInputImage()}. 128 * @return a new ImageWriter instance. 129 */ newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages)130 public static @NonNull ImageWriter newInstance(@NonNull Surface surface, 131 @IntRange(from = 1) int maxImages) { 132 return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN); 133 } 134 135 /** 136 * <p> 137 * Create a new ImageWriter with given number of max Images and format. 138 * </p> 139 * <p> 140 * The {@code maxImages} parameter determines the maximum number of 141 * {@link Image} objects that can be be dequeued from the 142 * {@code ImageWriter} simultaneously. Requesting more buffers will use up 143 * more memory, so it is important to use only the minimum number necessary. 144 * </p> 145 * <p> 146 * The format specifies the image format of this ImageWriter. The format 147 * from the {@code surface} will be overridden with this format. For example, 148 * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default 149 * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter 150 * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate 151 * with {@link ImageFormat#PRIVATE} Images. 152 * </p> 153 * <p> 154 * Note that the consumer end-point may or may not be able to support Images with different 155 * format, for such case, the application should only use this method if the consumer is able 156 * to consume such images. 157 * </p> 158 * <p> 159 * The input Image size depends on the Surface that is provided by 160 * the downstream consumer end-point. 161 * </p> 162 * 163 * @param surface The destination Surface this writer produces Image data 164 * into. 165 * @param maxImages The maximum number of Images the user will want to 166 * access simultaneously for producing Image data. This should be 167 * as small as possible to limit memory use. Once maxImages 168 * Images are dequeued by the user, one of them has to be queued 169 * back before a new Image can be dequeued for access via 170 * {@link #dequeueInputImage()}. 171 * @param format The format of this ImageWriter. It can be any valid format specified by 172 * {@link ImageFormat} or {@link PixelFormat}. 173 * 174 * @return a new ImageWriter instance. 175 */ newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format)176 public static @NonNull ImageWriter newInstance(@NonNull Surface surface, 177 @IntRange(from = 1) int maxImages, @Format int format) { 178 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { 179 throw new IllegalArgumentException("Invalid format is specified: " + format); 180 } 181 return new ImageWriter(surface, maxImages, format); 182 } 183 184 /** 185 * @hide 186 */ ImageWriter(Surface surface, int maxImages, int format)187 protected ImageWriter(Surface surface, int maxImages, int format) { 188 if (surface == null || maxImages < 1) { 189 throw new IllegalArgumentException("Illegal input argument: surface " + surface 190 + ", maxImages: " + maxImages); 191 } 192 193 mMaxImages = maxImages; 194 195 // Note that the underlying BufferQueue is working in synchronous mode 196 // to avoid dropping any buffers. 197 mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format); 198 199 // nativeInit internally overrides UNKNOWN format. So does surface format query after 200 // nativeInit and before getEstimatedNativeAllocBytes(). 201 if (format == ImageFormat.UNKNOWN) { 202 format = SurfaceUtils.getSurfaceFormat(surface); 203 } 204 // Estimate the native buffer allocation size and register it so it gets accounted for 205 // during GC. Note that this doesn't include the buffers required by the buffer queue 206 // itself and the buffers requested by the producer. 207 // Only include memory for 1 buffer, since actually accounting for the memory used is 208 // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some 209 // size. 210 Size surfSize = SurfaceUtils.getSurfaceSize(surface); 211 mEstimatedNativeAllocBytes = 212 ImageUtils.getEstimatedNativeAllocBytes(surfSize.getWidth(),surfSize.getHeight(), 213 format, /*buffer count*/ 1); 214 VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes); 215 } 216 217 /** 218 * <p> 219 * Maximum number of Images that can be dequeued from the ImageWriter 220 * simultaneously (for example, with {@link #dequeueInputImage()}). 221 * </p> 222 * <p> 223 * An Image is considered dequeued after it's returned by 224 * {@link #dequeueInputImage()} from ImageWriter, and until the Image is 225 * sent back to ImageWriter via {@link #queueInputImage}, or 226 * {@link Image#close()}. 227 * </p> 228 * <p> 229 * Attempting to dequeue more than {@code maxImages} concurrently will 230 * result in the {@link #dequeueInputImage()} function throwing an 231 * {@link IllegalStateException}. 232 * </p> 233 * 234 * @return Maximum number of Images that can be dequeued from this 235 * ImageWriter. 236 * @see #dequeueInputImage 237 * @see #queueInputImage 238 * @see Image#close 239 */ getMaxImages()240 public int getMaxImages() { 241 return mMaxImages; 242 } 243 244 /** 245 * <p> 246 * Dequeue the next available input Image for the application to produce 247 * data into. 248 * </p> 249 * <p> 250 * This method requests a new input Image from ImageWriter. The application 251 * owns this Image after this call. Once the application fills the Image 252 * data, it is expected to return this Image back to ImageWriter for 253 * downstream consumer components (e.g. 254 * {@link android.hardware.camera2.CameraDevice}) to consume. The Image can 255 * be returned to ImageWriter via {@link #queueInputImage} or 256 * {@link Image#close()}. 257 * </p> 258 * <p> 259 * This call will block if all available input images have been queued by 260 * the application and the downstream consumer has not yet consumed any. 261 * When an Image is consumed by the downstream consumer and released, an 262 * {@link OnImageReleasedListener#onImageReleased} callback will be fired, 263 * which indicates that there is one input Image available. For non- 264 * {@link ImageFormat#PRIVATE PRIVATE} formats ( 265 * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is 266 * recommended to dequeue the next Image only after this callback is fired, 267 * in the steady state. 268 * </p> 269 * <p> 270 * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} ( 271 * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the 272 * image buffer is accessible to the application only through the hardware 273 * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android 274 * versions prior to P, dequeueing private buffers will cause an 275 * {@link IllegalStateException} to be thrown). Alternatively, 276 * the application can acquire images from some other component (e.g. an 277 * {@link ImageReader}), and queue them directly to this ImageWriter via the 278 * {@link ImageWriter#queueInputImage queueInputImage()} method. 279 * </p> 280 * 281 * @return The next available input Image from this ImageWriter. 282 * @throws IllegalStateException if {@code maxImages} Images are currently 283 * dequeued, or the input {@link android.view.Surface Surface} 284 * has been abandoned by the consumer component that provided 285 * the {@link android.view.Surface Surface}. Prior to Android 286 * P, throws if the ImageWriter format is 287 * {@link ImageFormat#PRIVATE PRIVATE}. 288 * @see #queueInputImage 289 * @see Image#close 290 */ dequeueInputImage()291 public Image dequeueInputImage() { 292 if (mDequeuedImages.size() >= mMaxImages) { 293 throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages); 294 } 295 WriterSurfaceImage newImage = new WriterSurfaceImage(this); 296 nativeDequeueInputImage(mNativeContext, newImage); 297 mDequeuedImages.add(newImage); 298 newImage.mIsImageValid = true; 299 return newImage; 300 } 301 302 /** 303 * <p> 304 * Queue an input {@link Image} back to ImageWriter for the downstream 305 * consumer to access. 306 * </p> 307 * <p> 308 * The input {@link Image} could be from ImageReader (acquired via 309 * {@link ImageReader#acquireNextImage} or 310 * {@link ImageReader#acquireLatestImage}), or from this ImageWriter 311 * (acquired via {@link #dequeueInputImage}). In the former case, the Image 312 * data will be moved to this ImageWriter. Note that the Image properties 313 * (size, format, strides, etc.) must be the same as the properties of the 314 * images dequeued from this ImageWriter, or this method will throw an 315 * {@link IllegalArgumentException}. In the latter case, the application has 316 * filled the input image with data. This method then passes the filled 317 * buffer to the downstream consumer. In both cases, it's up to the caller 318 * to ensure that the Image timestamp (in nanoseconds) is correctly set, as 319 * the downstream component may want to use it to indicate the Image data 320 * capture time. 321 * </p> 322 * <p> 323 * After this method is called and the downstream consumer consumes and 324 * releases the Image, an {@link OnImageReleasedListener#onImageReleased} 325 * callback will fire. The application can use this callback to avoid 326 * sending Images faster than the downstream consumer processing rate in 327 * steady state. 328 * </p> 329 * <p> 330 * Passing in an Image from some other component (e.g. an 331 * {@link ImageReader}) requires a free input Image from this ImageWriter as 332 * the destination. In this case, this call will block, as 333 * {@link #dequeueInputImage} does, if there are no free Images available. 334 * To avoid blocking, the application should ensure that there is at least 335 * one free Image available in this ImageWriter before calling this method. 336 * </p> 337 * <p> 338 * After this call, the input Image is no longer valid for further access, 339 * as if the Image is {@link Image#close closed}. Attempting to access the 340 * {@link ByteBuffer ByteBuffers} returned by an earlier 341 * {@link Image.Plane#getBuffer Plane#getBuffer} call will result in an 342 * {@link IllegalStateException}. 343 * </p> 344 * 345 * @param image The Image to be queued back to ImageWriter for future 346 * consumption. 347 * @throws IllegalStateException if the image was already queued previously, 348 * or the image was aborted previously, or the input 349 * {@link android.view.Surface Surface} has been abandoned by the 350 * consumer component that provided the 351 * {@link android.view.Surface Surface}. 352 * @see #dequeueInputImage() 353 */ queueInputImage(Image image)354 public void queueInputImage(Image image) { 355 if (image == null) { 356 throw new IllegalArgumentException("image shouldn't be null"); 357 } 358 boolean ownedByMe = isImageOwnedByMe(image); 359 if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) { 360 throw new IllegalStateException("Image from ImageWriter is invalid"); 361 } 362 363 // For images from other components, need to detach first, then attach. 364 if (!ownedByMe) { 365 if (!(image.getOwner() instanceof ImageReader)) { 366 throw new IllegalArgumentException("Only images from ImageReader can be queued to" 367 + " ImageWriter, other image source is not supported yet!"); 368 } 369 370 ImageReader prevOwner = (ImageReader) image.getOwner(); 371 372 prevOwner.detachImage(image); 373 attachAndQueueInputImage(image); 374 // This clears the native reference held by the original owner. 375 // When this Image is detached later by this ImageWriter, the 376 // native memory won't be leaked. 377 image.close(); 378 return; 379 } 380 381 Rect crop = image.getCropRect(); 382 nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), crop.left, crop.top, 383 crop.right, crop.bottom, image.getTransform(), image.getScalingMode()); 384 385 /** 386 * Only remove and cleanup the Images that are owned by this 387 * ImageWriter. Images detached from other owners are only temporarily 388 * owned by this ImageWriter and will be detached immediately after they 389 * are released by downstream consumers, so there is no need to keep 390 * track of them in mDequeuedImages. 391 */ 392 if (ownedByMe) { 393 mDequeuedImages.remove(image); 394 // Do not call close here, as close is essentially cancel image. 395 WriterSurfaceImage wi = (WriterSurfaceImage) image; 396 wi.clearSurfacePlanes(); 397 wi.mIsImageValid = false; 398 } 399 } 400 401 /** 402 * Get the ImageWriter format. 403 * <p> 404 * This format may be different than the Image format returned by 405 * {@link Image#getFormat()}. However, if the ImageWriter format is 406 * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()} 407 * will result in an {@link IllegalStateException}. 408 * </p> 409 * 410 * @return The ImageWriter format. 411 */ getFormat()412 public int getFormat() { 413 return mWriterFormat; 414 } 415 416 /** 417 * ImageWriter callback interface, used to to asynchronously notify the 418 * application of various ImageWriter events. 419 */ 420 public interface OnImageReleasedListener { 421 /** 422 * <p> 423 * Callback that is called when an input Image is released back to 424 * ImageWriter after the data consumption. 425 * </p> 426 * <p> 427 * The client can use this callback to be notified that an input Image 428 * has been consumed and released by the downstream consumer. More 429 * specifically, this callback will be fired for below cases: 430 * <li>The application dequeues an input Image via the 431 * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method, 432 * uses it, and then queues it back to this ImageWriter via the 433 * {@link ImageWriter#queueInputImage queueInputImage()} method. After 434 * the downstream consumer uses and releases this image to this 435 * ImageWriter, this callback will be fired. This image will be 436 * available to be dequeued after this callback.</li> 437 * <li>The application obtains an Image from some other component (e.g. 438 * an {@link ImageReader}), uses it, and then queues it to this 439 * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}. 440 * After the downstream consumer uses and releases this image to this 441 * ImageWriter, this callback will be fired.</li> 442 * </p> 443 * 444 * @param writer the ImageWriter the callback is associated with. 445 * @see ImageWriter 446 * @see Image 447 */ onImageReleased(ImageWriter writer)448 void onImageReleased(ImageWriter writer); 449 } 450 451 /** 452 * Register a listener to be invoked when an input Image is returned to the 453 * ImageWriter. 454 * 455 * @param listener The listener that will be run. 456 * @param handler The handler on which the listener should be invoked, or 457 * null if the listener should be invoked on the calling thread's 458 * looper. 459 * @throws IllegalArgumentException If no handler specified and the calling 460 * thread has no looper. 461 */ setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler)462 public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) { 463 synchronized (mListenerLock) { 464 if (listener != null) { 465 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); 466 if (looper == null) { 467 throw new IllegalArgumentException( 468 "handler is null but the current thread is not a looper"); 469 } 470 if (mListenerHandler == null || mListenerHandler.getLooper() != looper) { 471 mListenerHandler = new ListenerHandler(looper); 472 } 473 mListener = listener; 474 } else { 475 mListener = null; 476 mListenerHandler = null; 477 } 478 } 479 } 480 481 /** 482 * Free up all the resources associated with this ImageWriter. 483 * <p> 484 * After calling this method, this ImageWriter cannot be used. Calling any 485 * methods on this ImageWriter and Images previously provided by 486 * {@link #dequeueInputImage()} will result in an 487 * {@link IllegalStateException}, and attempting to write into 488 * {@link ByteBuffer ByteBuffers} returned by an earlier 489 * {@link Image.Plane#getBuffer Plane#getBuffer} call will have undefined 490 * behavior. 491 * </p> 492 */ 493 @Override close()494 public void close() { 495 setOnImageReleasedListener(null, null); 496 for (Image image : mDequeuedImages) { 497 image.close(); 498 } 499 mDequeuedImages.clear(); 500 nativeClose(mNativeContext); 501 mNativeContext = 0; 502 503 if (mEstimatedNativeAllocBytes > 0) { 504 VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes); 505 mEstimatedNativeAllocBytes = 0; 506 } 507 } 508 509 @Override finalize()510 protected void finalize() throws Throwable { 511 try { 512 close(); 513 } finally { 514 super.finalize(); 515 } 516 } 517 518 /** 519 * <p> 520 * Attach and queue input Image to this ImageWriter. 521 * </p> 522 * <p> 523 * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or 524 * the source Image is so large that copying its data is too expensive, this 525 * method can be used to migrate the source Image into ImageWriter without a 526 * data copy, and then queue it to this ImageWriter. The source Image must 527 * be detached from its previous owner already, or this call will throw an 528 * {@link IllegalStateException}. 529 * </p> 530 * <p> 531 * After this call, the ImageWriter takes ownership of this Image. This 532 * ownership will automatically be removed from this writer after the 533 * consumer releases this Image, that is, after 534 * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for 535 * closing this Image through {@link Image#close()} to free up the resources 536 * held by this Image. 537 * </p> 538 * 539 * @param image The source Image to be attached and queued into this 540 * ImageWriter for downstream consumer to use. 541 * @throws IllegalStateException if the Image is not detached from its 542 * previous owner, or the Image is already attached to this 543 * ImageWriter, or the source Image is invalid. 544 */ attachAndQueueInputImage(Image image)545 private void attachAndQueueInputImage(Image image) { 546 if (image == null) { 547 throw new IllegalArgumentException("image shouldn't be null"); 548 } 549 if (isImageOwnedByMe(image)) { 550 throw new IllegalArgumentException( 551 "Can not attach an image that is owned ImageWriter already"); 552 } 553 /** 554 * Throw ISE if the image is not attachable, which means that it is 555 * either owned by other entity now, or completely non-attachable (some 556 * stand-alone images are not backed by native gralloc buffer, thus not 557 * attachable). 558 */ 559 if (!image.isAttachable()) { 560 throw new IllegalStateException("Image was not detached from last owner, or image " 561 + " is not detachable"); 562 } 563 564 // TODO: what if attach failed, throw RTE or detach a slot then attach? 565 // need do some cleanup to make sure no orphaned 566 // buffer caused leak. 567 Rect crop = image.getCropRect(); 568 nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(), 569 image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom, 570 image.getTransform(), image.getScalingMode()); 571 } 572 573 /** 574 * This custom handler runs asynchronously so callbacks don't get queued 575 * behind UI messages. 576 */ 577 private final class ListenerHandler extends Handler { ListenerHandler(Looper looper)578 public ListenerHandler(Looper looper) { 579 super(looper, null, true /* async */); 580 } 581 582 @Override handleMessage(Message msg)583 public void handleMessage(Message msg) { 584 OnImageReleasedListener listener; 585 synchronized (mListenerLock) { 586 listener = mListener; 587 } 588 if (listener != null) { 589 listener.onImageReleased(ImageWriter.this); 590 } 591 } 592 } 593 594 /** 595 * Called from Native code when an Event happens. This may be called from an 596 * arbitrary Binder thread, so access to the ImageWriter must be 597 * synchronized appropriately. 598 */ postEventFromNative(Object selfRef)599 private static void postEventFromNative(Object selfRef) { 600 @SuppressWarnings("unchecked") 601 WeakReference<ImageWriter> weakSelf = (WeakReference<ImageWriter>) selfRef; 602 final ImageWriter iw = weakSelf.get(); 603 if (iw == null) { 604 return; 605 } 606 607 final Handler handler; 608 synchronized (iw.mListenerLock) { 609 handler = iw.mListenerHandler; 610 } 611 if (handler != null) { 612 handler.sendEmptyMessage(0); 613 } 614 } 615 616 /** 617 * <p> 618 * Abort the Images that were dequeued from this ImageWriter, and return 619 * them to this writer for reuse. 620 * </p> 621 * <p> 622 * This method is used for the cases where the application dequeued the 623 * Image, may have filled the data, but does not want the downstream 624 * component to consume it. The Image will be returned to this ImageWriter 625 * for reuse after this call, and the ImageWriter will immediately have an 626 * Image available to be dequeued. This aborted Image will be invisible to 627 * the downstream consumer, as if nothing happened. 628 * </p> 629 * 630 * @param image The Image to be aborted. 631 * @see #dequeueInputImage() 632 * @see Image#close() 633 */ abortImage(Image image)634 private void abortImage(Image image) { 635 if (image == null) { 636 throw new IllegalArgumentException("image shouldn't be null"); 637 } 638 639 if (!mDequeuedImages.contains(image)) { 640 throw new IllegalStateException("It is illegal to abort some image that is not" 641 + " dequeued yet"); 642 } 643 644 WriterSurfaceImage wi = (WriterSurfaceImage) image; 645 if (!wi.mIsImageValid) { 646 return; 647 } 648 649 /** 650 * We only need abort Images that are owned and dequeued by ImageWriter. 651 * For attached Images, no need to abort, as there are only two cases: 652 * attached + queued successfully, and attach failed. Neither of the 653 * cases need abort. 654 */ 655 cancelImage(mNativeContext, image); 656 mDequeuedImages.remove(image); 657 wi.clearSurfacePlanes(); 658 wi.mIsImageValid = false; 659 } 660 isImageOwnedByMe(Image image)661 private boolean isImageOwnedByMe(Image image) { 662 if (!(image instanceof WriterSurfaceImage)) { 663 return false; 664 } 665 WriterSurfaceImage wi = (WriterSurfaceImage) image; 666 if (wi.getOwner() != this) { 667 return false; 668 } 669 670 return true; 671 } 672 673 private static class WriterSurfaceImage extends android.media.Image { 674 private ImageWriter mOwner; 675 // This field is used by native code, do not access or modify. 676 private long mNativeBuffer; 677 private int mNativeFenceFd = -1; 678 private SurfacePlane[] mPlanes; 679 private int mHeight = -1; 680 private int mWidth = -1; 681 private int mFormat = -1; 682 // When this default timestamp is used, timestamp for the input Image 683 // will be generated automatically when queueInputBuffer is called. 684 private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE; 685 private long mTimestamp = DEFAULT_TIMESTAMP; 686 687 private int mTransform = 0; //Default no transform 688 private int mScalingMode = 0; //Default frozen scaling mode 689 WriterSurfaceImage(ImageWriter writer)690 public WriterSurfaceImage(ImageWriter writer) { 691 mOwner = writer; 692 } 693 694 @Override getFormat()695 public int getFormat() { 696 throwISEIfImageIsInvalid(); 697 698 if (mFormat == -1) { 699 mFormat = nativeGetFormat(); 700 } 701 return mFormat; 702 } 703 704 @Override getWidth()705 public int getWidth() { 706 throwISEIfImageIsInvalid(); 707 708 if (mWidth == -1) { 709 mWidth = nativeGetWidth(); 710 } 711 712 return mWidth; 713 } 714 715 @Override getHeight()716 public int getHeight() { 717 throwISEIfImageIsInvalid(); 718 719 if (mHeight == -1) { 720 mHeight = nativeGetHeight(); 721 } 722 723 return mHeight; 724 } 725 726 @Override getTransform()727 public int getTransform() { 728 throwISEIfImageIsInvalid(); 729 730 return mTransform; 731 } 732 733 @Override getScalingMode()734 public int getScalingMode() { 735 throwISEIfImageIsInvalid(); 736 737 return mScalingMode; 738 } 739 740 @Override getTimestamp()741 public long getTimestamp() { 742 throwISEIfImageIsInvalid(); 743 744 return mTimestamp; 745 } 746 747 @Override setTimestamp(long timestamp)748 public void setTimestamp(long timestamp) { 749 throwISEIfImageIsInvalid(); 750 751 mTimestamp = timestamp; 752 } 753 754 @Override getHardwareBuffer()755 public HardwareBuffer getHardwareBuffer() { 756 throwISEIfImageIsInvalid(); 757 758 return nativeGetHardwareBuffer(); 759 } 760 761 @Override getPlanes()762 public Plane[] getPlanes() { 763 throwISEIfImageIsInvalid(); 764 765 if (mPlanes == null) { 766 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat()); 767 mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat()); 768 } 769 770 return mPlanes.clone(); 771 } 772 773 @Override isAttachable()774 boolean isAttachable() { 775 throwISEIfImageIsInvalid(); 776 // Don't allow Image to be detached from ImageWriter for now, as no 777 // detach API is exposed. 778 return false; 779 } 780 781 @Override getOwner()782 ImageWriter getOwner() { 783 throwISEIfImageIsInvalid(); 784 785 return mOwner; 786 } 787 788 @Override getNativeContext()789 long getNativeContext() { 790 throwISEIfImageIsInvalid(); 791 792 return mNativeBuffer; 793 } 794 795 @Override close()796 public void close() { 797 if (mIsImageValid) { 798 getOwner().abortImage(this); 799 } 800 } 801 802 @Override finalize()803 protected final void finalize() throws Throwable { 804 try { 805 close(); 806 } finally { 807 super.finalize(); 808 } 809 } 810 clearSurfacePlanes()811 private void clearSurfacePlanes() { 812 if (mIsImageValid && mPlanes != null) { 813 for (int i = 0; i < mPlanes.length; i++) { 814 if (mPlanes[i] != null) { 815 mPlanes[i].clearBuffer(); 816 mPlanes[i] = null; 817 } 818 } 819 } 820 } 821 822 private class SurfacePlane extends android.media.Image.Plane { 823 private ByteBuffer mBuffer; 824 final private int mPixelStride; 825 final private int mRowStride; 826 827 // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is 828 // called SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer)829 private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) { 830 mRowStride = rowStride; 831 mPixelStride = pixelStride; 832 mBuffer = buffer; 833 /** 834 * Set the byteBuffer order according to host endianness (native 835 * order), otherwise, the byteBuffer order defaults to 836 * ByteOrder.BIG_ENDIAN. 837 */ 838 mBuffer.order(ByteOrder.nativeOrder()); 839 } 840 841 @Override getRowStride()842 public int getRowStride() { 843 throwISEIfImageIsInvalid(); 844 return mRowStride; 845 } 846 847 @Override getPixelStride()848 public int getPixelStride() { 849 throwISEIfImageIsInvalid(); 850 return mPixelStride; 851 } 852 853 @Override getBuffer()854 public ByteBuffer getBuffer() { 855 throwISEIfImageIsInvalid(); 856 return mBuffer; 857 } 858 clearBuffer()859 private void clearBuffer() { 860 // Need null check first, as the getBuffer() may not be called 861 // before an Image is closed. 862 if (mBuffer == null) { 863 return; 864 } 865 866 if (mBuffer.isDirect()) { 867 NioUtils.freeDirectBuffer(mBuffer); 868 } 869 mBuffer = null; 870 } 871 872 } 873 874 // Create the SurfacePlane object and fill the information nativeCreatePlanes(int numPlanes, int writerFmt)875 private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt); 876 nativeGetWidth()877 private synchronized native int nativeGetWidth(); 878 nativeGetHeight()879 private synchronized native int nativeGetHeight(); 880 nativeGetFormat()881 private synchronized native int nativeGetFormat(); 882 nativeGetHardwareBuffer()883 private synchronized native HardwareBuffer nativeGetHardwareBuffer(); 884 } 885 886 // Native implemented ImageWriter methods. nativeInit(Object weakSelf, Surface surface, int maxImgs, int format)887 private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs, 888 int format); 889 nativeClose(long nativeCtx)890 private synchronized native void nativeClose(long nativeCtx); 891 nativeDequeueInputImage(long nativeCtx, Image wi)892 private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi); 893 nativeQueueInputImage(long nativeCtx, Image image, long timestampNs, int left, int top, int right, int bottom, int transform, int scalingMode)894 private synchronized native void nativeQueueInputImage(long nativeCtx, Image image, 895 long timestampNs, int left, int top, int right, int bottom, int transform, 896 int scalingMode); 897 nativeAttachAndQueueImage(long nativeCtx, long imageNativeBuffer, int imageFormat, long timestampNs, int left, int top, int right, int bottom, int transform, int scalingMode)898 private synchronized native int nativeAttachAndQueueImage(long nativeCtx, 899 long imageNativeBuffer, int imageFormat, long timestampNs, int left, 900 int top, int right, int bottom, int transform, int scalingMode); 901 cancelImage(long nativeCtx, Image image)902 private synchronized native void cancelImage(long nativeCtx, Image image); 903 904 /** 905 * We use a class initializer to allow the native code to cache some field 906 * offsets. 907 */ nativeClassInit()908 private static native void nativeClassInit(); 909 910 static { 911 System.loadLibrary("media_jni"); nativeClassInit()912 nativeClassInit(); 913 } 914 } 915