ImageWriter

ImageWriter

ImageWriter 是一个用于在 android.view.Surface 中生成图像数据,并且可以被其他组件(例如 android.hardware.camera2.CameraDevice)消费的类。

​ 它允许应用程序将图像数据生成到指定的 Surface 中,供其他组件使用。可以从多种 Android API 类获取输入 Surface 对象,供 ImageWriter 生成数据,包括 MediaCodec(编码器)、android.hardware.camera2.CameraCaptureSession(重新处理输入)、ImageReader 等。

​ 图像数据被封装在 Image 对象中。要将图像数据生成到目标 Surface 中,应用程序可以通过 dequeueInputImage 方法获取一个输入 Image,然后向其中写入图像数据。可以同时获取多个这样的 Image 对象,并以任意顺序将其排队回去,数量受构造函数参数 maxImages 的限制。

​ 如果应用程序已经有了来自 ImageReaderImage,可以直接将此 Image 排队到 ImageWriter 中(通过 queueInputImage 方法),可能不需要进行缓冲区复制。即使 ImageWriter 的图像格式是 ImageFormat#PRIVATE,在 Android P 之前,这也是将图像排队到此类 ImageWriter 的唯一方法。从 Android P 开始,私有图像也可以通过它们的硬件缓冲区(在可用时)通过 Image#getHardwareBuffer() 方法访问。尝试访问私有图像的平面将返回一个空数组。

​ 一旦新的输入 Image 被排队到 ImageWriter 中,就由下游组件(例如 ImageReaderandroid.hardware.camera2.CameraDevice)来消费这些 Image。如果下游组件无法以与 ImageWriter 生产速率至少相同的速度消费这些 Image,则 dequeueInputImage 调用最终会阻塞,并且应用程序将不得不丢弃输入帧。

如果提供输入 Surface 的消费者组件放弃了该 Surface,则尝试对 Image 进行排队或出队操作时会抛出 IllegalStateException 异常。

newInstance(Surface,maxImages)

参数说明

  • surface:目标 Surface,表示该 ImageWriter 将把图像数据生成到这个 Surface 中。
  • maxImages:用户同时希望访问的最大 Image 数量。这个参数决定了可以同时从 ImageWriter 中出队的 Image 对象的最大数量。请求更多的缓冲区会使用更多的内存,因此应该尽量使用最小必要数量。

返回值

  • 返回一个新的 ImageWriter 实例。
Surface surface = ...; // 获取一个目标 Surface 对象,用于 ImageWriter 生成图像数据
int maxImages = 3; // 设置最大同时访问的 Image 数量

// 使用 newInstance 静态方法创建 ImageWriter 实例
ImageWriter imageWriter = ImageWriter.newInstance(surface, maxImages);

// 现在可以使用 imageWriter 对象进行操作,如出队或排队 Image 数据

在上面的示例中,我们首先获取一个目标 Surface 对象(surface),然后定义了最大同时访问的 Image 数量(maxImages)。接着,调用 ImageWriter.newInstance(surface, maxImages) 方法来创建一个新的 ImageWriter 实例(imageWriter)。创建完成后,我们可以使用这个 imageWriter 对象来操作 Image 数据,如出队或排队 Image

newInstance(Surface,maxImages,format,width,height)
  • 参数说明

    • surface:目标 Surface,表示该 ImageWriter 将把图像数据生成到这个 Surface 中。
    • maxImages:用户同时希望访问的最大 Image 数量。这个参数决定了可以同时从 ImageWriter 中出队的 Image 对象的最大数量。请求更多的缓冲区会使用更多的内存,因此应该尽量使用最小必要数量。
    • format:指定 ImageWriter 的图像格式,可以是任何由 ImageFormatPixelFormat 指定的有效格式。
    • width:输入图像的宽度。
    • height:输入图像的高度。

    返回值

    • 返回一个新的 ImageWriter 实例。
    Surface surface = ...; // 获取一个目标 Surface 对象,用于 ImageWriter 生成图像数据
    int maxImages = 3; // 设置最大同时访问的 Image 数量
    int format = ImageFormat.YUV_420_888; // 设置图像格式为 YUV_420_888
    int width = 1920; // 设置输入图像的宽度
    int height = 1080; // 设置输入图像的高度
    
    // 使用 newInstance 静态方法创建 ImageWriter 实例
    ImageWriter imageWriter = ImageWriter.newInstance(surface, maxImages, format, width, height);
    
    // 现在可以使用 imageWriter 对象进行操作,如出队或排队 Image 数据
    

    在上面的示例中,我们通过调用 ImageWriter.newInstance(surface, maxImages, format, width, height) 方法创建了一个新的 ImageWriter 实例(imageWriter)。我们指定了目标 Surfacesurface)、最大同时访问的 Image 数量(maxImages)、图像格式(format)以及输入图像的尺寸(widthheight)。创建完成后,我们可以使用这个 imageWriter 对象来操作 Image 数据,如出队或排队 Image

通常会更倾向于使用newInstance(Surface,maxImages)

  1. 简单性和默认行为: 第一个 newInstance 方法不需要显式指定图像格式和尺寸。它使用默认的图像格式 ImageFormat.UNKNOWN 和默认的尺寸 -1,这些默认值通常足够满足大多数情况。使用这个方法可以避免需要手动指定这些参数,简化了调用过程。
  2. 灵活性: 第一个方法不涉及显式设置图像格式和尺寸,使得它更具灵活性。它可以根据提供的 Surface 自动适应图像格式和尺寸,与下游消费者的要求一致。这对于快速生成图像数据而不需要详细设置的情况很有用。
  3. 适用性: 大多数情况下,应用程序不需要关注具体的图像格式和尺寸设置,而是希望快速创建一个 ImageWriter 实例以开始生成图像数据。第一个方法提供了一个简洁且常用的方式来实现这一目的。
  4. 避免错误: 第二个方法需要显式设置图像格式和尺寸,这增加了用户的责任和可能的错误。如果用户不了解或错误地设置了这些参数,可能会导致不可预见的问题或错误的图像生成行为。

因此,一般情况下,使用第一个 newInstance 方法更为常见和方便,特别是在只需生成图像数据而不需要关注详细设置的情况下。只有当需要显式控制图像格式和尺寸时,才会考虑使用第二个方法。

newInstance(Surface,maxImages,format)

参数说明

  • surface:目标 Surface,表示该 ImageWriter 将把图像数据生成到这个 Surface 中。
  • maxImages:用户同时希望访问的最大 Image 数量。这个参数决定了可以同时从 ImageWriter 中出队的 Image 对象的最大数量。请求更多的缓冲区会使用更多的内存,因此应该尽量使用最小必要数量。
  • format:指定 ImageWriter 的图像格式,可以是任何由 ImageFormatPixelFormat 指定的有效格式。

返回值

  • 返回一个新的 ImageWriter 实例。
Surface surface = ...; // 获取一个目标 Surface 对象,用于 ImageWriter 生成图像数据
int maxImages = 3; // 设置最大同时访问的 Image 数量
int format = ImageFormat.YUV_420_888; // 设置图像格式为 YUV_420_888

// 使用 newInstance 静态方法创建 ImageWriter 实例
ImageWriter imageWriter = ImageWriter.newInstance(surface, maxImages, format);

// 现在可以使用 imageWriter 对象进行操作,如出队或排队 Image 数据

在上面的示例中,我们通过调用 ImageWriter.newInstance(surface, maxImages, format) 方法创建了一个新的 ImageWriter 实例(imageWriter)。我们指定了目标 Surfacesurface)、最大同时访问的 Image 数量(maxImages)以及图像格式(format)。创建完成后,我们可以使用这个 imageWriter 对象来操作 Image 数据,如出队或排队 Image

getMaxImages()

方法说明

  • getMaxImages():获取可以同时从 ImageWriter 中出队的最大 Image 数量。

返回值

  • 返回一个整数,表示可以同时从 ImageWriter 中出队的最大 Image 数量。
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 获取可以同时从 ImageWriter 中出队的最大 Image 数量
int maxImages = imageWriter.getMaxImages();

System.out.println("Maximum number of Images that can be dequeued: " + maxImages);

在上面的示例中,我们通过调用 imageWriter.getMaxImages() 方法获取了可以同时从 ImageWriter 中出队的最大 Image 数量。这个值通常由创建 ImageWriter 时指定的 maxImages 参数确定。

getWidth() | getHeight()

getWidth()

  • 方法说明: 获取 Image 对象的预期实际宽度(以像素为单位)。
  • 返回值: 返回一个整数,表示 Image 对象的预期实际宽度。

getHeight()

  • 方法说明: 获取 Image 对象的高度(以像素为单位)。
  • 返回值: 返回一个整数,表示 Image 对象的高度。
Image image = ...; // 假设已经获取了一个 Image 对象

// 获取 Image 对象的宽度和高度
int width = image.getWidth();
int height = image.getHeight();

System.out.println("Image width: " + width);
System.out.println("Image height: " + height);

在上面的示例中,我们通过调用 image.getWidth()image.getHeight() 方法分别获取了 Image 对象的宽度和高度。这些值通常由创建 Image 对象时指定的宽度和高度参数确定,如果没有显式设置宽度和高度,则取决于提供 Surface 的终端消费者端点的默认值。

dequeueInputImage()

方法说明

  • 作用: 从 ImageWriter 中获取下一个可用的输入 Image,应用程序在此方法调用后拥有该 Image。应用程序在填充完 Image 数据后,应将该 Image 返回给 ImageWriter,以便下游消费者组件(例如 CameraDevice)进行消费。
  • 阻塞行为: 如果应用程序已将所有可用的输入 Image 排队,并且下游消费者尚未消费任何 Image,则此调用将阻塞。当下游消费者消费并释放一个 Image 时,将触发 OnImageReleasedListener#onImageReleased 回调,表示有一个新的输入 Image 可用。对于非 PRIVATE 格式的 ImageWriter(即 getFormat() != ImageFormat.PRIVATE),建议在此回调稳定状态下触发后再获取下一个 Image
  • 返回值: 返回获取到的下一个可用的输入 Image 对象。
  • 异常情况
    • 如果已经从 ImageWriter 中取出了最大数量(即 maxImages)的 Image,则抛出 IllegalStateException
    • 如果提供 Surface 的消费者组件放弃了输入 Surface,或者 ImageWriter 的格式为 PRIVATE,则抛出 IllegalStateException。在 Android P 之前,如果 ImageWriter 的格式为 PRIVATE,同样会抛出 IllegalStateException
public Image dequeueInputImage() {
    if (mDequeuedImages.size() >= mMaxImages) {
        throw new IllegalStateException(
                "Already dequeued max number of Images " + mMaxImages);
    }
    WriterSurfaceImage newImage = new WriterSurfaceImage(this);
    nativeDequeueInputImage(mNativeContext, newImage);
    mDequeuedImages.add(newImage);
    newImage.mIsImageValid = true;
    return newImage;
}

//使用

ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

try {
    // 获取下一个可用的输入 Image
    Image inputImage = imageWriter.dequeueInputImage();

    // 在这里填充 inputImage 的数据...

    // 将填充完数据的 inputImage 返回给 ImageWriter
    imageWriter.queueInputImage(inputImage);
} catch (IllegalStateException e) {
    // 处理异常情况
    e.printStackTrace();
}

queueInputImage(Image image)

方法说明

  • 作用: 将输入的 Image 排入队列,使得下游消费者可以访问。
  • 参数
    • image:要排入队列的 Image
  • 异常
    • 如果 imagenull,则抛出 IllegalArgumentException
    • 如果 image 已经被排入队列过,或者之前已经被丢弃过,或者输入的 Surface 已被消费者组件放弃,则抛出 IllegalStateException
  • 实现细节
    • 检查传入的 image 是否为 null,如果是则抛出异常。
    • 检查传入的 image 是否由当前 ImageWriter 拥有,如果是则进行下一步操作。
    • 根据 image 的类型,可能需要将其从先前的所有者中分离,然后再将其附加到当前 ImageWriter,以确保 image 可以被正确地排入队列。
    • 调用本地方法将 image 排入队列,传递相关参数,如时间戳、数据空间等。
    • 如果 image 由当前 ImageWriter 拥有,则从 mDequeuedImages 中移除该 image,并清理相关资源。
    • 如果 image 不是由当前 ImageWriter 拥有,则将其附加到当前 ImageWriter,然后再进行排队操作。
    • 最后,关闭 image 或清理其状态,以确保资源正确释放。

注意事项

  • 使用此方法前,请确保传入的 image 参数有效且未被排入队列过。
  • 调用此方法后,传入的 image 将不再有效,不应再对其进行访问。
  • 在传入 image 后,下游消费者将使用它,直到释放,并触发 OnImageReleasedListener#onImageReleased 回调。
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 从 ImageReader 中获取一个 Image
Image image = imageReader.acquireNextImage();

// 将获取的 Image 排入队列到 ImageWriter
imageWriter.queueInputImage(image);

// Image 使用完成后,不再需要对其进行操作,因为它已经被排入队列
// 下游消费者会在需要时处理该 Image

在上面的示例中,我们从 ImageReader 中获取了一个 Image,然后将其排入队列到 ImageWriter 中。在此之后,不再需要对该 Image 进行其他操作,因为它已经被排入队列,供下游消费者处理。

getFormat()

方法说明

  • 作用: 获取 ImageWriter 的图像格式。该格式可能与通过 Image 对象的 getFormat() 方法返回的图像格式不同。
  • 返回值: 返回一个整数,表示 ImageWriter 的图像格式。
  • 注意事项
    • 如果 ImageWriter 的格式为 PRIVATE(即 mWriterFormatImageFormat.PRIVATE),则调用 dequeueInputImage() 方法将导致抛出 IllegalStateException。在此情况下,无法直接从 ImageWriter 中获取图像数据,而需要通过其他方式获取图像数据并将其排队到 ImageWriter 中。
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 获取 ImageWriter 的图像格式
int writerFormat = imageWriter.getFormat();

System.out.println("ImageWriter format: " + writerFormat);

在上面的示例中,我们通过调用 imageWriter.getFormat() 方法获取了 ImageWriter 的图像格式。这个返回的整数值对应于 ImageFormat 中的常量,可以用于判断 ImageWriter 的图像格式是公共格式还是 PRIVATE 格式。

getUsage()

方法说明

  • 作用: 获取 ImageWriter 的使用标志(usage flag)。该标志表示 ImageWriter 的用途,例如用于输入、输出或其他特定的用途。
  • 返回值: 返回一个 long 类型的值,表示 ImageWriter 的使用标志。
  • 注意事项
    • 如果在创建 ImageWriter 实例时未调用 BuildersetUsage 方法设置使用标志,或者设置了无效的使用标志值,那么调用 getUsage() 方法可能返回无效的值。
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 获取 ImageWriter 的使用标志
long usage = imageWriter.getUsage();

System.out.println("ImageWriter usage flag: " + usage);

在上面的示例中,我们通过调用 imageWriter.getUsage() 方法获取了 ImageWriter 的使用标志。这个值可以用于确定 ImageWriter 的用途,例如用于输入、输出或其他特定的用途。注意,在使用此方法之前,应确保在创建 ImageWriter 时已经调用了 BuildersetUsage 方法来设置使用标志.

getHardwareBufferFormat()

方法说明

  • 作用: 获取 ImageWriter 的硬件缓冲区格式,这适用于使用构建器模式 ImageWriter.Builder 创建 ImageWriter 实例,并且在构建过程中使用了 BuildersetHardwareBufferFormatsetDataSpace 方法设置了硬件缓冲区格式和数据空间。
  • 返回值: 返回一个 int 类型的值,表示 ImageWriter 的硬件缓冲区格式。
  • 注意事项
    • 只有在使用 ImageWriter.Builder 创建 ImageWriter 实例,并且在构建过程中设置了硬件缓冲区格式和数据空间时,才能使用此方法获取硬件缓冲区格式。
    • 硬件缓冲区格式是指 ImageWriter 使用的硬件缓冲区的像素格式,例如 AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM 等。
ImageWriter.Builder builder = new ImageWriter.Builder(...);
// 设置硬件缓冲区格式和数据空间
builder.setHardwareBufferFormat(AHardwareBuffer.Format.RGBA_8888);
builder.setDataSpace(DataSpace.V0_SRGB);

ImageWriter imageWriter = builder.build(); // 创建 ImageWriter 实例

// 获取 ImageWriter 的硬件缓冲区格式
int hardwareBufferFormat = imageWriter.getHardwareBufferFormat();

System.out.println("ImageWriter hardwareBuffer format: " + hardwareBufferFormat);

在上面的示例中,我们使用 ImageWriter.Builder 构建了一个 ImageWriter 实例,并在构建过程中设置了硬件缓冲区格式和数据空间。然后,我们通过调用 imageWriter.getHardwareBufferFormat() 方法获取了 ImageWriter 的硬件缓冲区格式。这个值表示 ImageWriter 使用的硬件缓冲区的像素格式。

getDataSpace()

方法说明

  • 作用: 获取 ImageWriter 的数据空间,这适用于使用构建器模式 ImageWriter.Builder 创建 ImageWriter 实例,并且在构建过程中使用了 BuildersetDataSpace 方法设置了数据空间。
  • 返回值: 返回一个 int 类型的值,表示 ImageWriter 的数据空间。
  • 注意事项
    • 只有在使用 ImageWriter.Builder 创建 ImageWriter 实例,并且在构建过程中设置了数据空间时,才能使用此方法获取数据空间。
    • 数据空间是指 ImageWriter 使用的数据格式和颜色空间,例如 DataSpace.V0_SRGB 表示标准的 sRGB 颜色空间。
ImageWriter.Builder builder = new ImageWriter.Builder(...);
// 设置数据空间
builder.setDataSpace(DataSpace.V0_SRGB);

ImageWriter imageWriter = builder.build(); // 创建 ImageWriter 实例

// 获取 ImageWriter 的数据空间
int dataSpace = imageWriter.getDataSpace();

System.out.println("ImageWriter dataspace: " + dataSpace);

在上面的示例中,我们使用 ImageWriter.Builder 构建了一个 ImageWriter 实例,并在构建过程中设置了数据空间为 DataSpace.V0_SRGB。然后,我们通过调用 imageWriter.getDataSpace() 方法获取了 ImageWriter 的数据空间。这个值表示 ImageWriter 使用的数据格式和颜色空间。

OnImageReleasedListener
public interface OnImageReleasedListener {
    /**
     * <p>
     * Callback that is called when an input Image is released back to
     * ImageWriter after the data consumption.
     * </p>
     * <p>
     * The client can use this callback to be notified that an input Image
     * has been consumed and released by the downstream consumer. More
     * specifically, this callback will be fired for below cases:
     * <li>The application dequeues an input Image via the
     * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method,
     * uses it, and then queues it back to this ImageWriter via the
     * {@link ImageWriter#queueInputImage queueInputImage()} method. After
     * the downstream consumer uses and releases this image to this
     * ImageWriter, this callback will be fired. This image will be
     * available to be dequeued after this callback.</li>
     * <li>The application obtains an Image from some other component (e.g.
     * an {@link ImageReader}), uses it, and then queues it to this
     * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}.
     * After the downstream consumer uses and releases this image to this
     * ImageWriter, this callback will be fired.</li>
     * </p>
     *
     * @param writer the ImageWriter the callback is associated with.
     * @see ImageWriter
     * @see Image
     */
    void onImageReleased(ImageWriter writer);
}

OnImageReleasedListener 接口,用于监听当输入 Image 被消费并释放回 ImageWriter 时的回调事件。

接口说明

  • 作用OnImageReleasedListener 接口用于监听当输入 Image 被消费并释放回 ImageWriter 时的事件。当下游消费者使用完输入 Image 并将其释放回 ImageWriter 后,将触发此回调。
  • 方法
    • void onImageReleased(ImageWriter writer):当输入 Image 被消费并释放回 ImageWriter 时调用的回调方法。通过此回调,客户端可以得知输入 Image 已被消费和释放,并可以执行相应的处理。
  • 回调场景
    • 当应用程序通过 ImageWriterdequeueInputImage() 方法获取一个输入 Image,使用完后通过 queueInputImage() 方法将其返回给 ImageWriter,然后下游消费者使用并释放该 Image 后,将触发此回调。
    • 当应用程序从其他组件(例如 ImageReader)获取一个 Image,使用完后通过 queueInputImage() 方法将其传递给 ImageWriter,然后下游消费者使用并释放该 Image 后,同样会触发此回调。
  • 参数
    • writer:触发回调的 ImageWriter 实例。
// 创建一个 ImageWriter 实例
ImageWriter imageWriter = ...;

// 设置 OnImageReleasedListener 监听器
imageWriter.setOnImageReleasedListener(new ImageWriter.OnImageReleasedListener() {
    @Override
    public void onImageReleased(ImageWriter writer) {
        // 当输入 Image 被消费并释放回 ImageWriter 时触发该回调
        System.out.println("Image released back to ImageWriter");
        // 可以在这里执行相应的处理逻辑
    }
});

// 在使用完 Image 后将其返回给 ImageWriter
Image inputImage = imageWriter.dequeueInputImage();
// 处理 inputImage 数据...
imageWriter.queueInputImage(inputImage);
setOnImageReleasedListener

方法说明

  • 作用setOnImageReleasedListener() 方法用于注册一个监听器,当输入 Image 返回到 ImageWriter 时触发该监听器。
  • 参数
    • listener:要注册的监听器,当输入 Image 返回到 ImageWriter 时将调用该监听器的回调方法。
    • handler:指定回调方法执行的 Handler,如果为 null,则表示在调用线程的 Looper 上执行回调方法。
  • 异常
    • 如果未指定 handler 且调用线程没有 Looper,则抛出 IllegalArgumentException
  • 实现细节
    • 通过 synchronized 同步块确保线程安全。
    • 如果指定了 listener,则根据 handler 获取对应的 Looper
    • 如果 handlernull,则使用当前线程的 Looper。
    • 如果没有 Looper,则抛出异常。
    • 如果当前的 mListenerHandlernull 或者其 Looper 不同于获取到的 Looper,则创建一个新的 ListenerHandler
    • listenermListenerHandler 分别设置为传入的参数或 null
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 创建一个 OnImageReleasedListener 监听器
ImageWriter.OnImageReleasedListener listener = new ImageWriter.OnImageReleasedListener() {
    @Override
    public void onImageReleased(ImageWriter writer) {
        // 当输入 Image 被消费并释放回 ImageWriter 时触发该回调
        System.out.println("Image released back to ImageWriter");
        // 可以在这里执行相应的处理逻辑
    }
};

// 创建一个 Handler,用于指定回调执行的线程
Handler handler = new Handler(Looper.getMainLooper()); // 在主线程的 Looper 上执行回调

// 注册监听器
imageWriter.setOnImageReleasedListener(listener, handler);

在上面的示例中,我们创建了一个 ImageWriter.OnImageReleasedListener 监听器,并通过 setOnImageReleasedListener() 方法将其注册到 ImageWriter 实例中。当输入 Image 被消费并释放回 ImageWriter 时,将触发监听器的 onImageReleased() 回调方法。我们还通过 Handler 指定了回调方法在主线程的 Looper 上执行,以确保在主线程中处理回调逻辑。

attachAndQueueInputImage

方法说明

  • 作用: 将源 Image 附加到 ImageWriter 并将其排入队列,使得下游消费者可以使用该 Image
  • 参数
    • image:要附加和排入队列的源 Image
  • 异常
    • 如果 Image 没有从其先前的所有者中分离,或者 Image 已经附加到此 ImageWriter,或者源 Image 无效,则抛出 IllegalStateException
  • 实现细节
    • 检查传入的 image 是否为 null,如果是则抛出异常。
    • 检查传入的 image 是否已经属于当前 ImageWriter,如果是则抛出异常。
    • 检查传入的 image 是否可以附加,如果不可以则抛出异常。
    • 获取 image 的裁剪区域和硬件缓冲区格式。
    • 根据 image 的类型调用相应的本地方法来附加和排入队列。
    • 在附加和排入队列完成后,释放相关资源并关闭 image

注意事项

  • 使用此方法前,必须确保源 Image 已经从其先前的所有者中分离。
  • 调用此方法后,ImageWriter 将拥有该 Image,直到消费者使用并释放该 Image
  • 调用者需要负责在适当的时候关闭 Image,以释放其占用的资源。
ImageWriter imageWriter = ...; // 假设已经创建了一个 ImageWriter 实例

// 获取一个源 Image(例如从 ImageReader 中获取)
Image sourceImage = imageReader.acquireNextImage();

// 将源 Image 附加并排入队列到 ImageWriter
imageWriter.attachAndQueueInputImage(sourceImage);

// 使用完毕后,记得关闭源 Image
sourceImage.close();
ImageWriter.Builder

用于构建 ImageWriter 实例的构建器模式。构建器模式允许您设置 ImageWriter 实例的各种属性,然后通过 build() 方法创建相应的实例。

构造函数

java
Copy code
public Builder(@NonNull Surface surface)
  • 构造一个新的 ImageWriter.Builder 实例。
  • surface 参数是用于生产图像数据的目标 Surface

方法概述

  1. setWidthAndHeight(int width, int height)
    • 设置图像的宽度和高度。
    • 默认大小取决于由下游终端点提供的 Surface
  2. setMaxImages(int maxImages)
    • 设置图像的最大数量。
    • 默认值为 1。
  3. setImageFormat(int imageFormat)
    • 设置 ImageWriter 的图像格式。
    • 如果设置了此属性,则会覆盖 Surface 提供的默认格式。
  4. setHardwareBufferFormat(int hardwareBufferFormat)
    • 设置 ImageWriter 的硬件缓冲区格式。
    • setDataSpace 方法一起使用,用于替换 setImageFormat
  5. setDataSpace(int dataSpace)
    • 设置 ImageWriter 的数据空间。
  6. setUsage(long usage)
    • 设置 ImageWriter 的使用标志。
  7. build()
    • 构建并返回一个新的 ImageWriter 对象,根据设置的属性。

注意事项

  • 构建器模式允许逐步构建对象,通过设置不同的属性。
  • 每个方法都返回 Builder 实例,以便进行链式调用。
  • 构建器通过设置不同的属性来创建不同配置的 ImageWriter 实例
    public static final class Builder {
        private Surface mSurface;
        private int mWidth = -1;
        private int mHeight = -1;
        private int mMaxImages = 1;
        private int mImageFormat = ImageFormat.UNKNOWN;
        private long mUsage = -1;
        private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
        private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN;
        private boolean mUseSurfaceImageFormatInfo = true;
        private boolean mUseLegacyImageFormat = false;

        /**
         * Constructs a new builder for {@link ImageWriter}.
         *
         * @param surface The destination Surface this writer produces Image data into.
         *
         * @throws IllegalArgumentException if the surface is already abandoned.
         */
        public Builder(@NonNull Surface surface) {
            mSurface = surface;
        }

        /**
         * Set the width and height of images. Default size is dependent on the Surface that is
         * provided by the downstream end-point.
         *
         * @param width The width in pixels that will be passed to the producer.
         * @param height The height in pixels that will be passed to the producer.
         * @return the Builder instance with customized width and height.
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder setWidthAndHeight(@IntRange(from = 1) int width,
                @IntRange(from = 1) int height) {
            mWidth = width;
            mHeight = height;
            return this;
        }

        /**
         * Set the maximum number of images. Default value is 1.
         *
         * @param maxImages The maximum number of Images the user will want to access simultaneously
         *                  for producing Image data.
         * @return the Builder instance with customized usage value.
         */
        public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) {
            mMaxImages = maxImages;
            return this;
        }

        /**
         * Set the image format of this ImageWriter.
         * Default format depends on the Surface provided.
         *
         * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified
         *                    by {@link ImageFormat} or {@link PixelFormat}.
         * @return the Builder instance with customized image format.
         *
         * @throws IllegalArgumentException if {@code imageFormat} is invalid.
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder setImageFormat(@Format int imageFormat) {
            if (!ImageFormat.isPublicFormat(imageFormat)
                    && !PixelFormat.isPublicFormat(imageFormat)) {
                throw new IllegalArgumentException(
                        "Invalid imageFormat is specified: " + imageFormat);
            }
            mImageFormat = imageFormat;
            mUseLegacyImageFormat = true;
            mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
            mDataSpace = DataSpace.DATASPACE_UNKNOWN;
            mUseSurfaceImageFormatInfo = false;
            return this;
        }

        /**
         * Set the hardwareBuffer format of this ImageWriter. The default value is
         * {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}.
         *
         * <p>This function works together with {@link #setDataSpace} for an
         * {@link ImageWriter} instance. Setting at least one of these two replaces
         * {@link #setImageFormat} function.</p>
         *
         * @param hardwareBufferFormat The HardwareBuffer format of the image that this writer
         *                             will produce.
         * @return the Builder instance with customized buffer format.
         *
         * @see #setDataSpace
         * @see #setImageFormat
         */
        public @NonNull Builder setHardwareBufferFormat(
                @HardwareBuffer.Format int hardwareBufferFormat) {
            mHardwareBufferFormat = hardwareBufferFormat;
            mImageFormat = ImageFormat.UNKNOWN;
            mUseLegacyImageFormat = false;
            mUseSurfaceImageFormatInfo = false;
            return this;
        }

        /**
         * Set the dataspace of this ImageWriter.
         * The default value is {@link DataSpace#DATASPACE_UNKNOWN}.
         *
         * @param dataSpace The dataspace of the image that this writer will produce.
         * @return the builder instance with customized dataspace value.
         *
         * @see #setHardwareBufferFormat
         */
        public @NonNull Builder setDataSpace(@NamedDataSpace int dataSpace) {
            mDataSpace = dataSpace;
            mImageFormat = ImageFormat.UNKNOWN;
            mUseLegacyImageFormat = false;
            mUseSurfaceImageFormatInfo = false;
            return this;
        }

        /**
         * Set the usage flag of this ImageWriter.
         *
         * <p>If this function is not called, usage bit will be set
         * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not
         * {@link ImageFormat#PRIVATE PRIVATE}.</p>
         *
         * @param usage The intended usage of the images produced by this ImageWriter.
         * @return the Builder instance with customized usage flag.
         *
         * @see HardwareBuffer
         * @see #getUsage
         */
        public @NonNull Builder setUsage(@Usage long usage) {
            mUsage = usage;
            return this;
        }

        /**
         * Builds a new ImageWriter object.
         *
         * @return The new ImageWriter object.
         */
        public @NonNull ImageWriter build() {
            if (mUseLegacyImageFormat) {
                return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
                        mImageFormat, mWidth, mHeight, mUsage);
            } else {
                return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
                        mHardwareBufferFormat, mDataSpace, mWidth, mHeight, mUsage);
            }
        }
    }
Surface surface = ...; // 假设已经有一个 Surface 实例

// 创建一个 ImageWriter.Builder 对象
ImageWriter.Builder builder = new ImageWriter.Builder(surface);

// 设置图像的宽度和高度
builder.setWidthAndHeight(1920, 1080);

// 设置图像的最大数量
builder.setMaxImages(2);

// 设置图像格式为 JPEG
builder.setImageFormat(ImageFormat.JPEG);

// 设置硬件缓冲区格式为 RGBA_8888
builder.setHardwareBufferFormat(HardwareBuffer.RGBA_8888);

// 设置数据空间为 REC709
builder.setDataSpace(DataSpace.DATASPACE_V0_SCRGB_LINEAR);

// 构建 ImageWriter 对象
ImageWriter imageWriter = builder.build();

在上面的示例中,我们创建了一个 ImageWriter.Builder 对象,并设置了一些属性,最后通过 build() 方法构建了一个 ImageWriter 实例。通过构建器模式,可以根据需要定制 ImageWriter 对象的配置。

小结:

ImageWriter 类用于将图像数据写入指定的 Surface,供后续消费者(例如摄像头设备)使用。它允许应用程序创建、管理和操作图像,以便在图像流或其他图像数据源中使用。

主要特性和方法

  1. 图像写入
    • dequeueInputImage(): 从 ImageWriter 中获取下一个可用的输入图像。应用程序需要填充这些图像数据,然后通过 queueInputImage() 将其提交给消费者。
  2. 图像队列管理
    • queueInputImage(Image image): 将输入图像排入队列,供消费者使用。
    • setMaxImages(int maxImages): 设置 ImageWriter 允许同时排队的最大图像数量。
  3. 图像格式和属性
    • getFormat(): 获取 ImageWriter 的图像格式。
    • getWidth(), getHeight(): 获取图像的宽度和高度。
    • getMaxImages(): 获取 ImageWriter 允许的最大图像数量。
  4. 图像监听器和回调
    • setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler): 设置图像释放监听器,用于监控图像何时被消费者释放。
  5. 图像属性设置(Builder 模式)
    • ImageWriter.Builder: 通过构建器模式创建 ImageWriter 实例,可以逐步设置图像的参数,如图像格式、宽度、高度等。

使用示例

javaCopy code// 创建 ImageWriter 实例
ImageWriter imageWriter = ImageWriter.newInstance(surface, 2, ImageFormat.RGBA_8888);

// 获取图像并填充数据
Image image = imageWriter.dequeueInputImage();
if (image != null) {
    // 填充图像数据
    fillImageData(image);

    // 将图像提交给 ImageWriter
    imageWriter.queueInputImage(image);
}

// 设置图像释放监听器
imageWriter.setOnImageReleasedListener(new ImageWriter.OnImageReleasedListener() {
    @Override
    public void onImageReleased(ImageWriter writer) {
        // 处理图像释放事件
        Log.d(TAG, "Image released: " + writer);
    }
}, null);

以上示例演示了如何使用 ImageWriter 类创建图像、填充图像数据并提交给消费者。通过设置图像释放监听器,可以及时处理图像的释放事件。

总的来说,ImageWriter 类提供了一组功能丰富的方法,用于管理和操作图像数据,是 Android 图像处理和传输中重要的组件之一。

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值