Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61a682e8 authored by Leon Scroggins's avatar Leon Scroggins Committed by Android (Google) Code Review
Browse files

Merge changes from topics "FrameInfo", "_advanceFrame"

* changes:
  AImageDecoder: Add APIs for FrameInfo
  Add AImageDecoder _advanceFrame and _rewind
parents 7b632a57 ac9f749c
Loading
Loading
Loading
Loading
+375 −9
Original line number Diff line number Diff line
@@ -109,7 +109,19 @@ enum {
    /**
     * AImageDecoder did not recognize the format.
     */
    ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9
    ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9,
    /**
     * The animation has reached the end.
     */
    ANDROID_IMAGE_DECODER_FINISHED = -10,
    /**
     * This method cannot be called while the AImageDecoder is in its current
     * state. For example, various setters (like {@link AImageDecoder_setTargetSize})
     * can only be called while the AImageDecoder is set to decode the first
     * frame of an animation. This ensures that any blending and/or restoring
     * prior frames works correctly.
     */
    ANDROID_IMAGE_DECODER_INVALID_STATE = -11,
};

struct AImageDecoder;
@@ -127,7 +139,7 @@ struct AImageDecoder;
 * After creation, {@link AImageDecoder_getHeaderInfo} can be used to retrieve
 * information about the encoded image. Other functions, like
 * {@link AImageDecoder_setTargetSize}, can be used to specify how to decode, and
 * {@link AImageDecoder_decode} will decode into client provided memory.
 * {@link AImageDecoder_decodeImage} will decode into client provided memory.
 *
 * {@link AImageDecoder} objects are NOT thread-safe, and should not be shared across
 * threads.
@@ -240,6 +252,10 @@ void AImageDecoder_delete(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
/**
 * Choose the desired output format.
 *
 * If the encoded image represents an animation, this must be called while on
 * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
 * after calling {@link AImageDecoder_rewind}).
 *
 * Available since API level 30.
 *
 * @param format {@link AndroidBitmapFormat} to use for the output.
@@ -255,6 +271,8 @@ void AImageDecoder_delete(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
 *   {@link AndroidBitmapFormat}.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: The
 *   {@link AndroidBitmapFormat} is incompatible with the image.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
 *   the first frame.
 */
int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
        int32_t format) __INTRODUCED_IN(30);
@@ -266,6 +284,10 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
 * Pass true to this method to leave them unpremultiplied. This has no effect on an
 * opaque image.
 *
 * If the encoded image represents an animation, this must be called while on
 * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
 * after calling {@link AImageDecoder_rewind}).
 *
 * Available since API level 30.
 *
 * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
@@ -278,6 +300,8 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
 *   {@link AImageDecoder_setTargetSize}.
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
 *   {@link AImageDecoder} is null.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
 *   the first frame.
 */
int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
                                             bool unpremultipliedRequired) __INTRODUCED_IN(30);
@@ -288,6 +312,10 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
 * Ignored by {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
 * an {@link ADataSpace}.
 *
 * If the encoded image represents an animation, this must be called while on
 * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
 * after calling {@link AImageDecoder_rewind}).
 *
 * Available since API level 30.
 *
 * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
@@ -303,6 +331,8 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
 *   {@link AImageDecoder} is null or |dataspace| does not correspond to an
 *   {@link ADataSpace} value.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
 *   the first frame.
 */
int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspace)
        __INTRODUCED_IN(30);
@@ -316,6 +346,10 @@ int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspac
 * specified by width and height, and the output image will be the size of the
 * crop rect.
 *
 * If the encoded image represents an animation, this must be called while on
 * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
 * after calling {@link AImageDecoder_rewind}).
 *
 * Available since API level 30.
 *
 * @param width Width of the output (prior to cropping).
@@ -330,9 +364,11 @@ int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspac
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
 *   {@link AImageDecoder} is null.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_SCALE}: |width| or |height| is <= 0,
 *   the size is too big, any existing crop is not contained by the new image dimensions,
 *   or the scale is incompatible with a previous call to
 *   the size is too big, any existing crop is not contained by the new image
 *   dimensions, or the scale is incompatible with a previous call to
 *   {@link AImageDecoder_setUnpremultipliedRequired}(true).
 * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
 *   the first frame.
 */
int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width,
                                int32_t height) __INTRODUCED_IN(30);
@@ -374,6 +410,10 @@ int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int
 * the specified {@link ARect}. Clients will only need to allocate enough memory
 * for the cropped ARect.
 *
 * If the encoded image represents an animation, this must be called while on
 * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
 * after calling {@link AImageDecoder_rewind}).
 *
 * Available since API level 30.
 *
 * @param crop Rectangle describing a crop of the decode. It must be contained inside of
@@ -389,8 +429,10 @@ int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int
 *
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
 *   {@link AImageDecoder} is null or the crop is not contained by the
 *   {@link AImageDecoder} is null, or the crop is not contained by the
 *   (possibly scaled) image dimensions.
 * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
 *   the first frame.
 */
int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30);

@@ -472,6 +514,10 @@ int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(
 * {@link AImageDecoder_decodeImage} will premultiply pixels by default.
 *
 * Available since API level 30.
 *
 * Starting in API level 31, an AImageDecoder may contain multiple frames of an
 * animation, but this method still only reports whether the first frame has
 * alpha.
 */
int AImageDecoderHeaderInfo_getAlphaFlags(
        const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
@@ -518,8 +564,44 @@ size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODU
 * Available since API level 30.
 *
 * Starting in API level 31, it can be used to decode all of the frames of an
 * animated image (i.e. GIF, WebP, HEIF) using new APIs (TODO (scroggo): list
 * and describe here).
 * animated image (i.e. GIF, WebP, HEIF) using new APIs. Internally,
 * AImageDecoder keeps track of its "current frame" - that is, the frame that
 * will be decoded by a call to AImageDecoder_decodeImage. At creation time, the
 * current frame is always the first frame, and multiple calls to this method
 * will each decode the first frame. {@link AImageDecoder_advanceFrame} advances
 * the current frame to the following frame, so that future calls to this method
 * will decode that frame. Some frames may update only part of the image. They
 * may only update a sub-rectangle (see {@link
 * AImageDecoderFrameInfo_getFrameRect}), or they may have alpha (see
 * {@link AImageDecoderFrameInfo_hasAlphaWithinBounds}). In these cases, this
 * method assumes that the prior frame is still residing in the |pixels| buffer,
 * decodes only the new portion, and blends it with the buffer. Frames that change
 * the entire |pixels| buffer are "independent", and do not require the prior
 * frame to remain in the buffer. The first frame is always independent. A
 * sophisticated client can use information from the {@link AImageDecoderFrameInfo}
 * to determine whether other frames are independent, or what frames they rely on.
 *
 * If the current frame is marked {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS},
 * AImageDecoder_decodeImage will cache the |pixels| buffer prior to decoding
 * (note: this only happens for the first in a string of consecutive
 * ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS frames). After advancing to the
 * following frame, AImageDecoder_decodeImage will restore the cached buffer
 * prior to decoding that frame.
 *
 * Ignoring timing information, display, etc, a client wishing to decode all
 * frames of an animated image may conceptually use code like the following:
 *
 * while (true) {
 *   int result = AImageDecoder_decodeImage(decoder, pixels, stride, size);
 *   if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
 *
 *   // Display or save the image in |pixels|, keeping the buffer intact for
 *   // AImageDecoder to decode the next frame correctly.
 *   Application_viewImage(pixels);
 *
 *   result = AImageDecoder_advanceFrame(decoder);
 *   if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
 * }
 *
 * @param decoder Opaque object representing the decoder.
 * @param pixels On success, will be filled with the result
@@ -547,6 +629,10 @@ size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODU
 *   failed to seek.
 * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
 *   failure to allocate memory.
 * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
 *   more frames. No decoding occurred. The client must call
 *   {@link AImageDecoder_rewind} before calling
 *   {@link AImageDecoder_decodeImage} again.
 */
int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder,
                              void* _Nonnull pixels, size_t stride,
@@ -561,8 +647,8 @@ int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder,
 *
 * Introduced in API 31.
 *
 * This may require seeking past the first frame to verify whether
 * there is a following frame (e.g. for GIF).
 * A single frame GIF is considered to *not* be animated. This may require
 * seeking past the first frame to verify whether there is a following frame.
 *
 * Errors:
 * - returns false if |decoder| is null.
@@ -610,6 +696,286 @@ enum {
int32_t AImageDecoder_getRepeatCount(AImageDecoder* _Nonnull decoder);
        __INTRODUCED_IN(31);

/**
 * Advance to the next frame in the animation.
 *
 * Introduced in API 31.
 *
 * The AImageDecoder keeps track internally which frame it is ready to decode
 * (the "current frame"). Initially it is set to decode the first frame, and
 * each call to {@link AImageDecoder_decodeImage} will continue to decode
 * the same frame until this method (or {@link AImageDecoder_rewind})
 * is called.
 *
 * Note that this can be used to skip a frame without decoding it. But
 * some frames depend on (i.e. blend with) prior frames, and
 * AImageDecoder_decodeImage assumes that the prior frame is in the
 * |pixels| buffer. In addition, AImageDecoder_decodeImage handles caching and
 * restoring frames (see {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS}), so
 * skipping frames in an image with such frames may not produce the correct
 * results.
 *
 * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
 *         indicating the reason for the failure.
 *
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
 *   represents an image that is not animated (see
 *   {@link AImageDecoder_isAnimated}) or the AImageDecoder is null.
 * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The input appears
 *   to be truncated. The client must call {@link AImageDecoder_rewind}
 *   before calling {@link AImageDecoder_decodeImage} again.
 * - {@link ANDROID_IMAGE_DECODER_ERROR}: The input contains an error.
 *   The client must call  {@link AImageDecoder_rewind} before
 *   calling {@link AImageDecoder_decodeImage} again.
 * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
 *   more frames. The client must call {@link AImageDecoder_rewind}
 *   before calling {@link AImageDecoder_decodeImage} again.
 */
int AImageDecoder_advanceFrame(AImageDecoder* _Nonnull decoder)
        __INTRODUCED_IN(31);

/**
 * Return to the beginning of the animation.
 *
 * Introduced in API 31.
 *
 * After this call, the AImageDecoder will be ready to decode the
 * first frame of the animation. This can be called after reaching
 * the end of the animation or an error or in the middle of the
 * animation.
 *
 * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
 *         indicating the reason for the failure.
 *
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
 *   represents an image that is not animated (see
 *   {@link AImageDecoder_isAnimated}) or the AImageDecoder is
 *   null.
 * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset or file
 *   descriptor failed to seek.
 */
int AImageDecoder_rewind(AImageDecoder* _Nonnull decoder)
        __INTRODUCED_IN(31);

#endif // __ANDROID_API__ >= 31

struct AImageDecoderFrameInfo;

/**
 * Opaque handle to animation information about a single frame.
 *
 * Introduced in API 31
 *
 * The duration (retrieved with {@link AImageDecoderFrameInfo_getDuration}) is
 * necessary for clients to display the animation at the proper speed. The other
 * information is helpful for a client that wants to determine what frames are
 * independent (or what frames they depend on), but is unnecessary for
 * a simple client that wants to sequentially display all frames.
 */
typedef struct AImageDecoderFrameInfo AImageDecoderFrameInfo;

#if __ANDROID_API__ >= 31

/**
 * Create an uninitialized AImageDecoderFrameInfo.
 *
 * Introduced in API 31.
 *
 * This can be passed to {@link AImageDecoder_getFrameInfo} to fill
 * in information about the current frame. It may be reused.
 *
 * Must be deleted with {@link AImageDecoderFrameInfo_delete}.
 */
AImageDecoderFrameInfo* _Nullable AImageDecoderFrameInfo_create()
        __INTRODUCED_IN(31);

/**
 * Delete an AImageDecoderFrameInfo.
 *
 * Introduced in API 31.
 */
void AImageDecoderFrameInfo_delete(
        AImageDecoderFrameInfo* _Nullable info) __INTRODUCED_IN(31);

/**
 * Fill |info| with information about the current frame.
 *
 * Introduced in API 31.
 *
 * Initially, this will return information about the first frame.
 * {@link AImageDecoder_advanceFrame} and
 * {@link AImageDecoder_rewind} can be used to change which frame
 * is the current frame.
 *
 * If the image only has one frame, this will fill the {@link
 * AImageDecoderFrameInfo} with the encoded info, if any, or reasonable
 * defaults.
 *
 * @param decoder Opaque object representing the decoder.
 * @param info Opaque object to hold frame information. On success, will be
 *             filled with information regarding the current frame.
 * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
 *         indicating the reason for the failure.
 *
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is null.
 * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
 *   more frames. The client must call {@link AImageDecoder_rewind} to reset the
 *   current frame to a valid frame (0).
 */
int AImageDecoder_getFrameInfo(AImageDecoder* _Nonnull decoder,
        AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);

/**
 * Report the number of nanoseconds to show the current frame.
 *
 * Introduced in API 31.
 *
 * Errors:
 * - returns 0 if |info| is null.
 */
int64_t AImageDecoderFrameInfo_getDuration(
        const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);

/**
 * The rectangle of the image (within 0, 0,
 * {@link AImageDecoder_getWidth}, {@link AImageDecoder_getHeight})
 * updated by this frame.
 *
 * Introduced in API 31.
 *
 * Note that this is unaffected by calls to
 * {@link AImageDecoder_setTargetSize} or
 * {@link AImageDecoder_setCrop}.
 *
 * A frame may update only part of the image. This will always be
 * contained by the image’s dimensions.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles blending frames, so a simple
 * sequential client does not need this.
 *
 * Errors:
 * - returns an empty ARect if |info| is null.
 */
ARect AImageDecoderFrameInfo_getFrameRect(
        const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);

/**
 * Whether the new portion of this frame may contain alpha.
 *
 * Introduced in API 31.
 *
 * Note that this may differ from whether the composed frame has
 * alpha. If this frame does not fill the entire image dimensions
 * (see {@link AImageDecoderFrameInfo_getFrameRect}) or it blends
 * with an opaque frame, for example, the composed frame’s alpha
 * may not match. It is also conservative; for example, if a color
 * index-based frame has a color with alpha but does not use it,
 * this will still return true.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles blending frames, so a simple
 * sequential client does not need this.
 *
 * Errors:
 * - returns false if |info| is null.
 */
bool AImageDecoderFrameInfo_hasAlphaWithinBounds(
        const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);

#endif // __ANDROID_API__ >= 31

/**
 * How a frame is “disposed” before showing the next one.
 *
 * Introduced in API 31.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles disposing of frames, so a simple
 * sequential client does not need this.
 */
enum {
    // No disposal. The following frame will be drawn directly
    // on top of this one.
    ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE = 1,
    // The frame’s rectangle is cleared (by AImageDecoder) before
    // decoding the next frame.
    ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND = 2,
    // The frame’s rectangle is reverted (by AImageDecoder) to the
    // prior frame before decoding the next frame.
    ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS = 3,
};

#if __ANDROID_API__ >= 31

/**
 * Return how this frame is “disposed” before showing the next one.
 *
 * Introduced in API 31.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles disposing of frames, so a simple
 * sequential client does not need this.
 *
 * @return one of:
 * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE}
 * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND}
 * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS}
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if |info| is null.
 */
int32_t AImageDecoderFrameInfo_getDisposeOp(
        const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);

#endif // __ANDROID_API__ >= 31

/**
 * How a frame is blended with the previous frame.
 *
 * Introduced in API 31.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles blending frames, so a simple
 * sequential client does not need this.
 */
enum {
    // This frame replaces existing content. This corresponds
    // to webp’s “do not blend”.
    ANDROID_IMAGE_DECODER_BLEND_OP_SRC = 1,
    // This frame blends with the previous frame.
    ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER = 2,
};

#if __ANDROID_API__ >= 31

/**
 * Return how this frame is blended with the previous frame.
 *
 * Introduced in API 31.
 *
 * This, along with other information in AImageDecoderFrameInfo,
 * can be useful for determining whether a frame is independent, but
 * the decoder handles blending frames, so a simple
 * sequential client does not need this.
 *
 * @return one of:
 * - {@link ANDROID_IMAGE_DECODER_BLEND_OP_SRC}
 * - {@link ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER}
 * Errors:
 * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if |info| is null.
 */
int32_t AImageDecoderFrameInfo_getBlendOp(
        const AImageDecoderFrameInfo* _Nonnull info)
        __INTRODUCED_IN(31);

#endif // __ANDROID_API__ >= 31

#ifdef __cplusplus