Implement FrameInfo methods on AImageDecoder

Bug: 160984428
Test: If47d475233f6b9973abf68029b63a610ff47cdae

- AImageDecoder_getFrameInfo
- AImageDecoderFrameInfo_create
- AImageDecoderFrameInfo_delete
- AImageDecoderFrameInfo_getDuration
- AImageDecoderFrameInfo_getFrameRect
- AImageDecoderFrameInfo_getDisposeOp
- AImageDecoderFrameInfo_getBlendOp
- AImageDecoderFrameInfo_hasAlphaWithinBounds

These allow querying for information specific to a single frame in an
encoded image.

Change-Id: I6ce5665e9c25aed23f99ce88290e520d68fcb60e
This commit is contained in:
Leon Scroggins III
2020-12-28 15:31:48 -05:00
parent b26aebc325
commit 0621313fe6
4 changed files with 114 additions and 0 deletions

View File

@@ -282,6 +282,35 @@ bool ImageDecoder::advanceFrame() {
return true;
}
SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
LOG_ALWAYS_FATAL_IF(finished());
auto dims = mCodec->codec()->dimensions();
SkCodec::FrameInfo info;
if (!mCodec->codec()->getFrameInfo(mOptions.fFrameIndex, &info)) {
// SkCodec may return false for a non-animated image. Provide defaults.
info.fRequiredFrame = SkCodec::kNoFrame;
info.fDuration = 0;
info.fFullyReceived = true;
info.fAlphaType = mCodec->codec()->getInfo().alphaType();
info.fHasAlphaWithinBounds = info.fAlphaType != kOpaque_SkAlphaType;
info.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
info.fBlend = SkCodecAnimation::Blend::kSrc;
info.fFrameRect = SkIRect::MakeSize(dims);
}
if (auto origin = mCodec->codec()->getOrigin(); origin != kDefault_SkEncodedOrigin) {
if (SkEncodedOriginSwapsWidthHeight(origin)) {
dims = swapped(dims);
}
auto matrix = SkEncodedOriginToMatrix(origin, dims.width(), dims.height());
auto rect = SkRect::Make(info.fFrameRect);
LOG_ALWAYS_FATAL_IF(!matrix.mapRect(&rect));
rect.roundIn(&info.fFrameRect);
}
return info;
}
bool ImageDecoder::finished() const {
return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount();
}

View File

@@ -71,6 +71,8 @@ public:
bool isAnimated();
int currentFrame() const;
SkCodec::FrameInfo getCurrentFrameInfo();
private:
// State machine for keeping track of how to handle RestorePrevious (RP)
// frames in decode().

View File

@@ -429,3 +429,78 @@ int AImageDecoder_rewind(AImageDecoder* decoder) {
return imageDecoder->rewind() ? ANDROID_IMAGE_DECODER_SUCCESS
: ANDROID_IMAGE_DECODER_SEEK_ERROR;
}
AImageDecoderFrameInfo* AImageDecoderFrameInfo_create() {
return reinterpret_cast<AImageDecoderFrameInfo*>(new SkCodec::FrameInfo);
}
static SkCodec::FrameInfo* toFrameInfo(AImageDecoderFrameInfo* info) {
return reinterpret_cast<SkCodec::FrameInfo*>(info);
}
static const SkCodec::FrameInfo* toFrameInfo(const AImageDecoderFrameInfo* info) {
return reinterpret_cast<const SkCodec::FrameInfo*>(info);
}
void AImageDecoderFrameInfo_delete(AImageDecoderFrameInfo* info) {
delete toFrameInfo(info);
}
int AImageDecoder_getFrameInfo(AImageDecoder* decoder,
AImageDecoderFrameInfo* info) {
if (!decoder || !info) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
auto* imageDecoder = toDecoder(decoder);
if (imageDecoder->finished()) {
return ANDROID_IMAGE_DECODER_FINISHED;
}
*toFrameInfo(info) = imageDecoder->getCurrentFrameInfo();
return ANDROID_IMAGE_DECODER_SUCCESS;
}
int64_t AImageDecoderFrameInfo_getDuration(const AImageDecoderFrameInfo* info) {
if (!info) return 0;
return toFrameInfo(info)->fDuration * 1'000'000;
}
ARect AImageDecoderFrameInfo_getFrameRect(const AImageDecoderFrameInfo* info) {
if (!info) {
return { 0, 0, 0, 0};
}
const SkIRect& r = toFrameInfo(info)->fFrameRect;
return { r.left(), r.top(), r.right(), r.bottom() };
}
bool AImageDecoderFrameInfo_hasAlphaWithinBounds(const AImageDecoderFrameInfo* info) {
if (!info) return false;
return toFrameInfo(info)->fHasAlphaWithinBounds;
}
int32_t AImageDecoderFrameInfo_getDisposeOp(const AImageDecoderFrameInfo* info) {
if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kKeep)
== ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE);
static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestoreBGColor)
== ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND);
static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestorePrevious)
== ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS);
return static_cast<int>(toFrameInfo(info)->fDisposalMethod);
}
int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) {
if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
switch (toFrameInfo(info)->fBlend) {
case SkCodecAnimation::Blend::kSrc:
return ANDROID_IMAGE_DECODER_BLEND_OP_SRC;
case SkCodecAnimation::Blend::kSrcOver:
return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER;
}
}

View File

@@ -17,12 +17,20 @@ LIBJNIGRAPHICS {
AImageDecoder_getRepeatCount; # introduced=31
AImageDecoder_advanceFrame; # introduced=31
AImageDecoder_rewind; # introduced=31
AImageDecoder_getFrameInfo; # introduced = 31
AImageDecoderHeaderInfo_getWidth; # introduced=30
AImageDecoderHeaderInfo_getHeight; # introduced=30
AImageDecoderHeaderInfo_getMimeType; # introduced=30
AImageDecoderHeaderInfo_getAlphaFlags; # introduced=30
AImageDecoderHeaderInfo_getAndroidBitmapFormat; # introduced=30
AImageDecoderHeaderInfo_getDataSpace; # introduced=30
AImageDecoderFrameInfo_create; # introduced = 31
AImageDecoderFrameInfo_delete; # introduced = 31
AImageDecoderFrameInfo_getDuration; # introduced = 31
AImageDecoderFrameInfo_getFrameRect; # introduced = 31
AImageDecoderFrameInfo_hasAlphaWithinBounds; # introduced = 31
AImageDecoderFrameInfo_getDisposeOp; # introduced = 31
AImageDecoderFrameInfo_getBlendOp; # introduced = 31
AndroidBitmap_getInfo;
AndroidBitmap_getDataSpace;
AndroidBitmap_lockPixels;