Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2018 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkAndroidCodec.h"
      9 #include "SkAnimatedImage.h"
     10 #include "SkCanvas.h"
     11 #include "SkCodec.h"
     12 #include "SkCodecPriv.h"
     13 #include "SkImagePriv.h"
     14 #include "SkPicture.h"
     15 #include "SkPictureRecorder.h"
     16 #include "SkPixelRef.h"
     17 
     18 sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
     19         SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
     20     if (!codec) {
     21         return nullptr;
     22     }
     23 
     24     SkISize decodeSize = scaledSize;
     25     auto decodeInfo = codec->getInfo();
     26     if (codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP
     27             && scaledSize.width()  < decodeInfo.width()
     28             && scaledSize.height() < decodeInfo.height()) {
     29         // libwebp can decode to arbitrary smaller sizes.
     30         decodeInfo = decodeInfo.makeWH(decodeSize.width(), decodeSize.height());
     31     }
     32 
     33     auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
     34                 decodeInfo, cropRect, std::move(postProcess)));
     35     if (!image->fDisplayFrame.fBitmap.getPixels()) {
     36         // tryAllocPixels failed.
     37         return nullptr;
     38     }
     39 
     40     return image;
     41 }
     42 
     43 sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
     44     if (!codec) {
     45         return nullptr;
     46     }
     47 
     48     const auto decodeInfo = codec->getInfo();
     49     const auto scaledSize = decodeInfo.dimensions();
     50     const auto cropRect   = SkIRect::MakeSize(scaledSize);
     51     auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
     52                 decodeInfo, cropRect, nullptr));
     53 
     54     if (!image->fDisplayFrame.fBitmap.getPixels()) {
     55         // tryAllocPixels failed.
     56         return nullptr;
     57     }
     58 
     59     SkASSERT(image->fSimple);
     60     return image;
     61 }
     62 
     63 SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
     64         SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
     65     : fCodec(std::move(codec))
     66     , fScaledSize(scaledSize)
     67     , fDecodeInfo(decodeInfo)
     68     , fCropRect(cropRect)
     69     , fPostProcess(std::move(postProcess))
     70     , fFrameCount(fCodec->codec()->getFrameCount())
     71     , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess
     72               && fCropRect == fDecodeInfo.bounds())
     73     , fFinished(false)
     74     , fRepetitionCount(fCodec->codec()->getRepetitionCount())
     75     , fRepetitionsCompleted(0)
     76 {
     77     if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
     78         return;
     79     }
     80 
     81     if (!fSimple) {
     82         fMatrix = SkMatrix::MakeTrans(-fCropRect.fLeft, -fCropRect.fTop);
     83         float scaleX = (float) fScaledSize.width()  / fDecodeInfo.width();
     84         float scaleY = (float) fScaledSize.height() / fDecodeInfo.height();
     85         fMatrix.preConcat(SkMatrix::MakeScale(scaleX, scaleY));
     86     }
     87     this->decodeNextFrame();
     88 }
     89 
     90 SkAnimatedImage::~SkAnimatedImage() { }
     91 
     92 SkRect SkAnimatedImage::onGetBounds() {
     93     return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
     94 }
     95 
     96 SkAnimatedImage::Frame::Frame()
     97     : fIndex(SkCodec::kNone)
     98 {}
     99 
    100 bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) {
    101     if (fBitmap.getPixels()) {
    102         if (fBitmap.pixelRef()->unique()) {
    103             SkAssertResult(fBitmap.setAlphaType(info.alphaType()));
    104             return true;
    105         }
    106 
    107         // An SkCanvas provided to onDraw is still holding a reference.
    108         // Copy before we decode to ensure that we don't overwrite the
    109         // expected contents of the image.
    110         if (OnInit::kRestoreIfNecessary == onInit) {
    111             SkBitmap tmp;
    112             if (!tmp.tryAllocPixels(info)) {
    113                 return false;
    114             }
    115 
    116             memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
    117             SkTSwap(tmp, fBitmap);
    118             return true;
    119         }
    120     }
    121 
    122     return fBitmap.tryAllocPixels(info);
    123 }
    124 
    125 bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
    126     if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
    127         return false;
    128     }
    129 
    130     memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
    131     dst->fIndex = fIndex;
    132     dst->fDisposalMethod = fDisposalMethod;
    133     return true;
    134 }
    135 
    136 void SkAnimatedImage::reset() {
    137     fFinished = false;
    138     fRepetitionsCompleted = 0;
    139     if (fDisplayFrame.fIndex != 0) {
    140         fDisplayFrame.fIndex = SkCodec::kNone;
    141         this->decodeNextFrame();
    142     }
    143 }
    144 
    145 static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
    146     return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
    147 }
    148 
    149 int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
    150     SkASSERT(animationEnded != nullptr);
    151     *animationEnded = false;
    152 
    153     const int frameToDecode = current + 1;
    154     if (frameToDecode == fFrameCount - 1) {
    155         // Final frame. Check to determine whether to stop.
    156         fRepetitionsCompleted++;
    157         if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
    158                 && fRepetitionsCompleted > fRepetitionCount) {
    159             *animationEnded = true;
    160         }
    161     } else if (frameToDecode == fFrameCount) {
    162         return 0;
    163     }
    164     return frameToDecode;
    165 }
    166 
    167 double SkAnimatedImage::finish() {
    168     fFinished = true;
    169     fCurrentFrameDuration = kFinished;
    170     return kFinished;
    171 }
    172 
    173 int SkAnimatedImage::decodeNextFrame() {
    174     if (fFinished) {
    175         return kFinished;
    176     }
    177 
    178     bool animationEnded = false;
    179     int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
    180 
    181     SkCodec::FrameInfo frameInfo;
    182     if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
    183         if (!frameInfo.fFullyReceived) {
    184             SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
    185             return this->finish();
    186         }
    187 
    188         fCurrentFrameDuration = frameInfo.fDuration;
    189     } else {
    190         animationEnded = true;
    191         if (0 == frameToDecode) {
    192             // Static image. This is okay.
    193             frameInfo.fRequiredFrame = SkCodec::kNone;
    194             frameInfo.fAlphaType = fCodec->getInfo().alphaType();
    195             frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
    196             // These fields won't be read.
    197             frameInfo.fDuration = INT_MAX;
    198             frameInfo.fFullyReceived = true;
    199             fCurrentFrameDuration = kFinished;
    200         } else {
    201             SkCodecPrintf("Error getting frameInfo for frame %i\n",
    202                           frameToDecode);
    203             return this->finish();
    204         }
    205     }
    206 
    207     if (frameToDecode == fDisplayFrame.fIndex) {
    208         if (animationEnded) {
    209             return this->finish();
    210         }
    211         return fCurrentFrameDuration;
    212     }
    213 
    214     for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
    215         if (frameToDecode == frame->fIndex) {
    216             SkTSwap(fDisplayFrame, *frame);
    217             if (animationEnded) {
    218                 return this->finish();
    219             }
    220             return fCurrentFrameDuration;
    221         }
    222     }
    223 
    224     // The following code makes an effort to avoid overwriting a frame that will
    225     // be used again. If frame |i| is_restore_previous, frame |i+1| will not
    226     // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
    227     // for frame |i+1|.
    228     // We could be even smarter about which frames to save by looking at the
    229     // entire dependency chain.
    230     SkCodec::Options options;
    231     options.fFrameIndex = frameToDecode;
    232     if (frameInfo.fRequiredFrame == SkCodec::kNone) {
    233         if (is_restore_previous(frameInfo.fDisposalMethod)) {
    234             // frameToDecode will be discarded immediately after drawing, so
    235             // do not overwrite a frame which could possibly be used in the
    236             // future.
    237             if (fDecodingFrame.fIndex != SkCodec::kNone &&
    238                     !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
    239                 SkTSwap(fDecodingFrame, fRestoreFrame);
    240             }
    241         }
    242     } else {
    243         auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
    244             if (SkCodec::kNone == frame.fIndex || is_restore_previous(frame.fDisposalMethod)) {
    245                 return false;
    246             }
    247 
    248             return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
    249         };
    250         if (validPriorFrame(fDecodingFrame)) {
    251             if (is_restore_previous(frameInfo.fDisposalMethod)) {
    252                 // fDecodingFrame is a good frame to use for this one, but we
    253                 // don't want to overwrite it.
    254                 fDecodingFrame.copyTo(&fRestoreFrame);
    255             }
    256             options.fPriorFrame = fDecodingFrame.fIndex;
    257         } else if (validPriorFrame(fDisplayFrame)) {
    258             if (!fDisplayFrame.copyTo(&fDecodingFrame)) {
    259                 SkCodecPrintf("Failed to allocate pixels for frame\n");
    260                 return this->finish();
    261             }
    262             options.fPriorFrame = fDecodingFrame.fIndex;
    263         } else if (validPriorFrame(fRestoreFrame)) {
    264             if (!is_restore_previous(frameInfo.fDisposalMethod)) {
    265                 SkTSwap(fDecodingFrame, fRestoreFrame);
    266             } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
    267                 SkCodecPrintf("Failed to restore frame\n");
    268                 return this->finish();
    269             }
    270             options.fPriorFrame = fDecodingFrame.fIndex;
    271         }
    272     }
    273 
    274     auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
    275                      kOpaque_SkAlphaType : kPremul_SkAlphaType;
    276     auto info = fDecodeInfo.makeAlphaType(alphaType);
    277     SkBitmap* dst = &fDecodingFrame.fBitmap;
    278     if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
    279         return this->finish();
    280     }
    281 
    282     auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
    283                                              &options);
    284     if (result != SkCodec::kSuccess) {
    285         SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
    286         return this->finish();
    287     }
    288 
    289     fDecodingFrame.fIndex = frameToDecode;
    290     fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
    291 
    292     SkTSwap(fDecodingFrame, fDisplayFrame);
    293     fDisplayFrame.fBitmap.notifyPixelsChanged();
    294 
    295     if (animationEnded) {
    296         return this->finish();
    297     }
    298     return fCurrentFrameDuration;
    299 }
    300 
    301 void SkAnimatedImage::onDraw(SkCanvas* canvas) {
    302     auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
    303                                              kNever_SkCopyPixelsMode);
    304 
    305     if (fSimple) {
    306         canvas->drawImage(image, 0, 0);
    307         return;
    308     }
    309 
    310     SkRect bounds = this->getBounds();
    311     if (fPostProcess) {
    312         canvas->saveLayer(&bounds, nullptr);
    313     }
    314     {
    315         SkAutoCanvasRestore acr(canvas, fPostProcess);
    316         canvas->concat(fMatrix);
    317         SkPaint paint;
    318         paint.setFilterQuality(kLow_SkFilterQuality);
    319         canvas->drawImage(image, 0, 0, &paint);
    320     }
    321     if (fPostProcess) {
    322         canvas->drawPicture(fPostProcess);
    323         canvas->restore();
    324     }
    325 }
    326 
    327 void SkAnimatedImage::setRepetitionCount(int newCount) {
    328     fRepetitionCount = newCount;
    329 }
    330