content: /*
   * Copyright (C) 2013 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.media;
  
  import java.nio.ByteBuffer;
  import java.lang.AutoCloseable;
  
  import android.annotation.Nullable;
  import android.annotation.UnsupportedAppUsage;
  import android.graphics.Rect;
  import android.hardware.HardwareBuffer;
  
  /**
   * <p>A single complete image buffer to use with a media source such as a
   * {@link MediaCodec} or a
   * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
   *
   * <p>This class allows for efficient direct application access to the pixel
   * data of the Image through one or more
   * {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
   * {@link Plane} that describes the layout of the pixel data in that plane. Due
   * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
   * Images are not directly usable as UI resources.</p>
   *
   * <p>Since Images are often directly produced or consumed by hardware
   * components, they are a limited resource shared across the system, and should
   * be closed as soon as they are no longer needed.</p>
   *
   * <p>For example, when using the {@link ImageReader} class to read out Images
   * from various media sources, not closing old Image objects will prevent the
   * availability of new Images once
   * {@link ImageReader#getMaxImages the maximum outstanding image count} is
   * reached. When this happens, the function acquiring new Images will typically
   * throw an {@link IllegalStateException}.</p>
   *
   * @see ImageReader
   */
  public abstract class Image implements AutoCloseable {
      /**
       * @hide
       */
      protected boolean mIsImageValid = false;
  
      /**
       * @hide
       */
      @UnsupportedAppUsage
      protected Image() {
      }
  
      /**
       * Throw IllegalStateException if the image is invalid (already closed).
       *
       * @hide
       */
      protected void throwISEIfImageIsInvalid() {
          if (!mIsImageValid) {
              throw new IllegalStateException("Image is already closed");
          }
      }
      /**
       * Get the format for this image. This format determines the number of
       * ByteBuffers needed to represent the image, and the general layout of the
       * pixel data in each ByteBuffer.
       *
       * <p>
       * The format is one of the values from
       * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
       * formats and the planes is as follows:
       * </p>
       *
       * <table>
       * <tr>
       *   <th>Format</th>
       *   <th>Plane count</th>
       *   <th>Layout details</th>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
       *   <td>1</td>
       *   <td>Compressed data, so row and pixel strides are 0. To uncompress, use
       *      {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
       *   </td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
       *   <td>3</td>
       *   <td>A luminance plane followed by the Cb and Cr chroma planes.
       *     The chroma planes have half the width and height of the luminance
       *     plane (4:2:0 subsampling). Each pixel sample in each plane has 8 bits.
       *     Each plane has its own row stride and pixel stride.</td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#YUV_422_888 YUV_422_888}</td>
       *   <td>3</td>
       *   <td>A luminance plane followed by the Cb and Cr chroma planes.
       *     The chroma planes have half the width and the full height of the luminance
       *     plane (4:2:2 subsampling). Each pixel sample in each plane has 8 bits.
       *     Each plane has its own row stride and pixel stride.</td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#YUV_444_888 YUV_444_888}</td>
       *   <td>3</td>
       *   <td>A luminance plane followed by the Cb and Cr chroma planes.
       *     The chroma planes have the same width and height as that of the luminance
       *     plane (4:4:4 subsampling). Each pixel sample in each plane has 8 bits.
       *     Each plane has its own row stride and pixel stride.</td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#FLEX_RGB_888 FLEX_RGB_888}</td>
       *   <td>3</td>
       *   <td>A R (red) plane followed by the G (green) and B (blue) planes.
       *     All planes have the same widths and heights.
       *     Each pixel sample in each plane has 8 bits.
       *     Each plane has its own row stride and pixel stride.</td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#FLEX_RGBA_8888 FLEX_RGBA_8888}</td>
       *   <td>4</td>
       *   <td>A R (red) plane followed by the G (green), B (blue), and
       *     A (alpha) planes. All planes have the same widths and heights.
       *     Each pixel sample in each plane has 8 bits.
       *     Each plane has its own row stride and pixel stride.</td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
       *   <td>1</td>
       *   <td>A single plane of raw sensor image data, with 16 bits per color
       *     sample. The details of the layout need to be queried from the source of
       *     the raw sensor data, such as
       *     {@link android.hardware.camera2.CameraDevice CameraDevice}.
       *   </td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE}</td>
       *   <td>1</td>
       *   <td>A single plane of raw sensor image data of private layout.
       *   The details of the layout is implementation specific. Row stride and
       *   pixel stride are undefined for this format. Calling {@link Plane#getRowStride()}
       *   or {@link Plane#getPixelStride()} on RAW_PRIVATE image will cause
       *   UnSupportedOperationException being thrown.
       *   </td>
       * </tr>
       * <tr>
       *   <td>{@link android.graphics.ImageFormat#HEIC HEIC}</td>
       *   <td>1</td>
       *   <td>Compressed data, so row and pixel strides are 0. To uncompress, use
       *      {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
       *   </td>
       * </tr>
       * </table>
       *
       * @see android.graphics.ImageFormat
       */
      public abstract int getFormat();
  
      /**
       * The width of the image in pixels. For formats where some color channels
       * are subsampled, this is the width of the largest-resolution plane.
       */
      public abstract int getWidth();
  
      /**
       * The height of the image in pixels. For formats where some color channels
       * are subsampled, this is the height of the largest-resolution plane.
       */
      public abstract int getHeight();
  
      /**
       * Get the timestamp associated with this frame.
       * <p>
       * The timestamp is measured in nanoseconds, and is normally monotonically
       * increasing. The timestamps for the images from different sources may have
       * different timebases therefore may not be comparable. The specific meaning and
       * timebase of the timestamp depend on the source providing images. See
       * {@link android.hardware.Camera Camera},
       * {@link android.hardware.camera2.CameraDevice CameraDevice},
       * {@link MediaPlayer} and {@link MediaCodec} for more details.
       * </p>
       */
      public abstract long getTimestamp();
  
      /**
       * Get the transformation associated with this frame.
       * @return The window transformation that needs to be applied for this frame.
       * @hide
       */
      public abstract int getTransform();
  
      /**
       * Get the scaling mode associated with this frame.
       * @return The scaling mode that needs to be applied for this frame.
       * @hide
       */
      public abstract int getScalingMode();
  
      /**
       * Get the {@link android.hardware.HardwareBuffer HardwareBuffer} handle of the input image
       * intended for GPU and/or hardware access.
       * <p>
       * The returned {@link android.hardware.HardwareBuffer HardwareBuffer} shall not be used
       * after  {@link Image#close Image.close()} has been called.
       * </p>
       * @return the HardwareBuffer associated with this Image or null if this Image doesn't support
       * this feature. (Unsupported use cases include Image instances obtained through
       * {@link android.media.MediaCodec MediaCodec}, and on versions prior to Android P,
       * {@link android.media.ImageWriter ImageWriter}).
       */
      @Nullable
      public HardwareBuffer getHardwareBuffer() {
          throwISEIfImageIsInvalid();
          return null;
      }
  
      /**
       * Set the timestamp associated with this frame.
       * <p>
       * The timestamp is measured in nanoseconds, and is normally monotonically
       * increasing. The timestamps for the images from different sources may have
       * different timebases therefore may not be comparable. The specific meaning and
       * timebase of the timestamp depend on the source providing images. See
       * {@link android.hardware.Camera Camera},
       * {@link android.hardware.camera2.CameraDevice CameraDevice},
       * {@link MediaPlayer} and {@link MediaCodec} for more details.
       * </p>
       * <p>
       * For images dequeued from {@link ImageWriter} via
       * {@link ImageWriter#dequeueInputImage()}, it's up to the application to
       * set the timestamps correctly before sending them back to the
       * {@link ImageWriter}, or the timestamp will be generated automatically when
       * {@link ImageWriter#queueInputImage queueInputImage()} is called.
       * </p>
       *
       * @param timestamp The timestamp to be set for this image.
       */
      public void setTimestamp(long timestamp) {
          throwISEIfImageIsInvalid();
          return;
      }
  
      private Rect mCropRect;
  
      /**
       * Get the crop rectangle associated with this frame.
       * <p>
       * The crop rectangle specifies the region of valid pixels in the image,
       * using coordinates in the largest-resolution plane.
       */
      public Rect getCropRect() {
          throwISEIfImageIsInvalid();
  
          if (mCropRect == null) {
              return new Rect(0, 0, getWidth(), getHeight());
          } else {
              return new Rect(mCropRect); // return a copy
          }
      }
  
      /**
       * Set the crop rectangle associated with this frame.
       * <p>
       * The crop rectangle specifies the region of valid pixels in the image,
       * using coordinates in the largest-resolution plane.
       */
      public void setCropRect(Rect cropRect) {
          throwISEIfImageIsInvalid();
  
          if (cropRect != null) {
              cropRect = new Rect(cropRect);  // make a copy
              if (!cropRect.intersect(0, 0, getWidth(), getHeight())) {
                  cropRect.setEmpty();
              }
          }
          mCropRect = cropRect;
      }
  
      /**
       * Get the array of pixel planes for this Image. The number of planes is
       * determined by the format of the Image. The application will get an empty
       * array if the image format is {@link android.graphics.ImageFormat#PRIVATE
       * PRIVATE}, because the image pixel data is not directly accessible. The
       * application can check the image format by calling
       * {@link Image#getFormat()}.
       */
      public abstract Plane[] getPlanes();
  
      /**
       * Free up this frame for reuse.
       * <p>
       * After calling this method, calling any methods on this {@code Image} will
       * result in an {@link IllegalStateException}, and attempting to read from
       * or write to {@link ByteBuffer ByteBuffers} returned by an earlier
       * {@link Plane#getBuffer} call will have undefined behavior. If the image
       * was obtained from {@link ImageWriter} via
       * {@link ImageWriter#dequeueInputImage()}, after calling this method, any
       * image data filled by the application will be lost and the image will be
       * returned to {@link ImageWriter} for reuse. Images given to
       * {@link ImageWriter#queueInputImage queueInputImage()} are automatically
       * closed.
       * </p>
       */
      @Override
      public abstract void close();
  
      /**
       * <p>
       * Check if the image can be attached to a new owner (e.g. {@link ImageWriter}).
       * </p>
       * <p>
       * This is a package private method that is only used internally.
       * </p>
       *
       * @return true if the image is attachable to a new owner, false if the image is still attached
       *         to its current owner, or the image is a stand-alone image and is not attachable to
       *         a new owner.
       */
      boolean isAttachable() {
          throwISEIfImageIsInvalid();
  
          return false;
      }
  
      /**
       * <p>
       * Get the owner of the {@link Image}.
       * </p>
       * <p>
       * The owner of an {@link Image} could be {@link ImageReader}, {@link ImageWriter},
       * {@link MediaCodec} etc. This method returns the owner that produces this image, or null
       * if the image is stand-alone image or the owner is unknown.
       * </p>
       * <p>
       * This is a package private method that is only used internally.
       * </p>
       *
       * @return The owner of the Image.
       */
      Object getOwner() {
          throwISEIfImageIsInvalid();
  
          return null;
      }
  
      /**
       * Get native context (buffer pointer) associated with this image.
       * <p>
       * This is a package private method that is only used internally. It can be
       * used to get the native buffer pointer and passed to native, which may be
       * passed to {@link ImageWriter#attachAndQueueInputImage} to avoid a reverse
       * JNI call.
       * </p>
       *
       * @return native context associated with this Image.
       */
      long getNativeContext() {
          throwISEIfImageIsInvalid();
  
          return 0;
      }
  
      /**
       * <p>A single color plane of image data.</p>
       *
       * <p>The number and meaning of the planes in an Image are determined by the
       * format of the Image.</p>
       *
       * <p>Once the Image has been closed, any access to the the plane's
       * ByteBuffer will fail.</p>
       *
       * @see #getFormat
       */
      public static abstract class Plane {
          /**
           * @hide
           */
          @UnsupportedAppUsage
          protected Plane() {
          }
  
          /**
           * <p>The row stride for this color plane, in bytes.</p>
           *
           * <p>This is the distance between the start of two consecutive rows of
           * pixels in the image. Note that row stride is undefined for some formats
           * such as
           * {@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE},
           * and calling getRowStride on images of these formats will
           * cause an UnsupportedOperationException being thrown.
           * For formats where row stride is well defined, the row stride
           * is always greater than 0.</p>
           */
          public abstract int getRowStride();
          /**
           * <p>The distance between adjacent pixel samples, in bytes.</p>
           *
           * <p>This is the distance between two consecutive pixel values in a row
           * of pixels. It may be larger than the size of a single pixel to
           * account for interleaved image data or padded formats.
           * Note that pixel stride is undefined for some formats such as
           * {@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE},
           * and calling getPixelStride on images of these formats will
           * cause an UnsupportedOperationException being thrown.
           * For formats where pixel stride is well defined, the pixel stride
           * is always greater than 0.</p>
           */
          public abstract int getPixelStride();
          /**
           * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
           * containing the frame data.</p>
           *
           * <p>In particular, the buffer returned will always have
           * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
           * the underlying data could be mapped as a pointer in JNI without doing
           * any copies with {@code GetDirectBufferAddress}.</p>
           *
           * <p>For raw formats, each plane is only guaranteed to contain data
           * up to the last pixel in the last row. In other words, the stride
           * after the last row may not be mapped into the buffer. This is a
           * necessary requirement for any interleaved format.</p>
           *
           * @return the byte buffer containing the image data for this plane.
           */
          public abstract ByteBuffer getBuffer();
      }
  
  }
  