blob: 014e21dd3a5e7211a39c8df3fdc6a2eea46d87a3 [file] [log] [blame]
Leon Scroggins III7a10b332018-01-12 11:24:30 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/android/SkAnimatedImage.h"
9#include "include/codec/SkAndroidCodec.h"
10#include "include/codec/SkCodec.h"
11#include "include/core/SkCanvas.h"
12#include "include/core/SkPicture.h"
13#include "include/core/SkPictureRecorder.h"
14#include "include/core/SkPixelRef.h"
15#include "src/codec/SkCodecPriv.h"
16#include "src/core/SkImagePriv.h"
Leon Scroggins III7a10b332018-01-12 11:24:30 -050017
Ben Wagner0b9b1f12019-04-04 18:00:05 -040018#include <limits.h>
Ben Wagnerf08d1d02018-06-18 15:11:00 -040019#include <utility>
20
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050021sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
Leon Scroggins III85463352019-02-04 15:22:10 -050022 const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
23 if (!codec) {
24 return nullptr;
25 }
26
27 auto scaledSize = requestedInfo.dimensions();
28 auto decodeInfo = requestedInfo;
29 if (codec->getEncodedFormat() != SkEncodedImageFormat::kWEBP
30 || scaledSize.width() >= decodeInfo.width()
31 || scaledSize.height() >= decodeInfo.height()) {
32 // Only libwebp can decode to arbitrary smaller sizes.
33 auto dims = codec->getInfo().dimensions();
Brian Salomon9241a6d2019-10-03 13:26:54 -040034 decodeInfo = decodeInfo.makeDimensions(dims);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050035 }
36
37 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
38 decodeInfo, cropRect, std::move(postProcess)));
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040039 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050040 // tryAllocPixels failed.
41 return nullptr;
42 }
43
44 return image;
45}
46
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050047sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
48 if (!codec) {
49 return nullptr;
50 }
51
52 const auto decodeInfo = codec->getInfo();
53 const auto scaledSize = decodeInfo.dimensions();
54 const auto cropRect = SkIRect::MakeSize(scaledSize);
55 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
56 decodeInfo, cropRect, nullptr));
57
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040058 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050059 // tryAllocPixels failed.
60 return nullptr;
61 }
62
63 SkASSERT(image->fSimple);
64 return image;
65}
66
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050067SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
68 SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050069 : fCodec(std::move(codec))
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050070 , fScaledSize(scaledSize)
71 , fDecodeInfo(decodeInfo)
72 , fCropRect(cropRect)
73 , fPostProcess(std::move(postProcess))
Leon Scroggins III4c119452018-01-20 10:33:24 -050074 , fFrameCount(fCodec->codec()->getFrameCount())
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050075 , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess
76 && fCropRect == fDecodeInfo.bounds())
Leon Scroggins III7a10b332018-01-12 11:24:30 -050077 , fFinished(false)
Leon Scroggins III4c119452018-01-20 10:33:24 -050078 , fRepetitionCount(fCodec->codec()->getRepetitionCount())
79 , fRepetitionsCompleted(0)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050080{
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040081 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050082 return;
83 }
84
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050085 if (!fSimple) {
Mike Reed1f607332020-05-21 12:11:27 -040086 fMatrix = SkMatrix::Translate(-fCropRect.fLeft, -fCropRect.fTop);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050087 float scaleX = (float) fScaledSize.width() / fDecodeInfo.width();
88 float scaleY = (float) fScaledSize.height() / fDecodeInfo.height();
Mike Reed1f607332020-05-21 12:11:27 -040089 fMatrix.preConcat(SkMatrix::Scale(scaleX, scaleY));
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050090 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -050091 this->decodeNextFrame();
Leon Scroggins III7a10b332018-01-12 11:24:30 -050092}
93
94SkAnimatedImage::~SkAnimatedImage() { }
95
96SkRect SkAnimatedImage::onGetBounds() {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050097 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
Leon Scroggins III7a10b332018-01-12 11:24:30 -050098}
99
100SkAnimatedImage::Frame::Frame()
Nigel Tao66bc5242018-08-22 10:56:03 +1000101 : fIndex(SkCodec::kNoFrame)
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500102{}
103
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400104bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) {
105 if (fBitmap.getPixels()) {
106 if (fBitmap.pixelRef()->unique()) {
107 SkAssertResult(fBitmap.setAlphaType(info.alphaType()));
108 return true;
109 }
110
111 // An SkCanvas provided to onDraw is still holding a reference.
112 // Copy before we decode to ensure that we don't overwrite the
113 // expected contents of the image.
114 if (OnInit::kRestoreIfNecessary == onInit) {
115 SkBitmap tmp;
116 if (!tmp.tryAllocPixels(info)) {
117 return false;
118 }
119
120 memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400121 using std::swap;
122 swap(tmp, fBitmap);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400123 return true;
124 }
125 }
126
127 return fBitmap.tryAllocPixels(info);
128}
129
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500130bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400131 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500132 return false;
133 }
134
135 memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
136 dst->fIndex = fIndex;
137 dst->fDisposalMethod = fDisposalMethod;
138 return true;
139}
140
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500141void SkAnimatedImage::reset() {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500142 fFinished = false;
143 fRepetitionsCompleted = 0;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400144 if (fDisplayFrame.fIndex != 0) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000145 fDisplayFrame.fIndex = SkCodec::kNoFrame;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400146 this->decodeNextFrame();
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500147 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500148}
149
150static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
151 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
152}
153
Leon Scroggins III4c119452018-01-20 10:33:24 -0500154int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
155 SkASSERT(animationEnded != nullptr);
156 *animationEnded = false;
157
158 const int frameToDecode = current + 1;
159 if (frameToDecode == fFrameCount - 1) {
160 // Final frame. Check to determine whether to stop.
161 fRepetitionsCompleted++;
162 if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
163 && fRepetitionsCompleted > fRepetitionCount) {
164 *animationEnded = true;
165 }
166 } else if (frameToDecode == fFrameCount) {
167 return 0;
168 }
169 return frameToDecode;
170}
171
172double SkAnimatedImage::finish() {
173 fFinished = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500174 fCurrentFrameDuration = kFinished;
175 return kFinished;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500176}
177
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500178int SkAnimatedImage::decodeNextFrame() {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500179 if (fFinished) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500180 return kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500181 }
182
Leon Scroggins III4c119452018-01-20 10:33:24 -0500183 bool animationEnded = false;
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400184 const int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500185
186 SkCodec::FrameInfo frameInfo;
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500187 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500188 if (!frameInfo.fFullyReceived) {
189 SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500190 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500191 }
192
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500193 fCurrentFrameDuration = frameInfo.fDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500194 } else {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500195 animationEnded = true;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500196 if (0 == frameToDecode) {
197 // Static image. This is okay.
Nigel Tao66bc5242018-08-22 10:56:03 +1000198 frameInfo.fRequiredFrame = SkCodec::kNoFrame;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500199 frameInfo.fAlphaType = fCodec->getInfo().alphaType();
Kevin Lubick289d36f2018-02-13 10:25:00 -0500200 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500201 // These fields won't be read.
202 frameInfo.fDuration = INT_MAX;
203 frameInfo.fFullyReceived = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500204 fCurrentFrameDuration = kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500205 } else {
206 SkCodecPrintf("Error getting frameInfo for frame %i\n",
207 frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500208 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500209 }
210 }
211
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400212 if (frameToDecode == fDisplayFrame.fIndex) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500213 if (animationEnded) {
214 return this->finish();
215 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500216 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500217 }
218
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400219 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
220 if (frameToDecode == frame->fIndex) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400221 using std::swap;
222 swap(fDisplayFrame, *frame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400223 if (animationEnded) {
224 return this->finish();
225 }
226 return fCurrentFrameDuration;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500227 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500228 }
229
230 // The following code makes an effort to avoid overwriting a frame that will
231 // be used again. If frame |i| is_restore_previous, frame |i+1| will not
232 // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
233 // for frame |i+1|.
234 // We could be even smarter about which frames to save by looking at the
235 // entire dependency chain.
236 SkCodec::Options options;
237 options.fFrameIndex = frameToDecode;
Nigel Tao66bc5242018-08-22 10:56:03 +1000238 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500239 if (is_restore_previous(frameInfo.fDisposalMethod)) {
240 // frameToDecode will be discarded immediately after drawing, so
241 // do not overwrite a frame which could possibly be used in the
242 // future.
Nigel Tao66bc5242018-08-22 10:56:03 +1000243 if (fDecodingFrame.fIndex != SkCodec::kNoFrame &&
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400244 !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400245 using std::swap;
246 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500247 }
248 }
249 } else {
250 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000251 if (SkCodec::kNoFrame == frame.fIndex ||
252 is_restore_previous(frame.fDisposalMethod)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500253 return false;
254 }
255
256 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
257 };
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400258 if (validPriorFrame(fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500259 if (is_restore_previous(frameInfo.fDisposalMethod)) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400260 // fDecodingFrame is a good frame to use for this one, but we
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500261 // don't want to overwrite it.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400262 fDecodingFrame.copyTo(&fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500263 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400264 options.fPriorFrame = fDecodingFrame.fIndex;
265 } else if (validPriorFrame(fDisplayFrame)) {
266 if (!fDisplayFrame.copyTo(&fDecodingFrame)) {
267 SkCodecPrintf("Failed to allocate pixels for frame\n");
268 return this->finish();
269 }
270 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500271 } else if (validPriorFrame(fRestoreFrame)) {
272 if (!is_restore_previous(frameInfo.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400273 using std::swap;
274 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400275 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500276 SkCodecPrintf("Failed to restore frame\n");
Leon Scroggins III4c119452018-01-20 10:33:24 -0500277 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500278 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400279 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500280 }
281 }
282
283 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
284 kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400285 auto info = fDecodeInfo.makeAlphaType(alphaType);
286 SkBitmap* dst = &fDecodingFrame.fBitmap;
287 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
288 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500289 }
290
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500291 auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
292 &options);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500293 if (result != SkCodec::kSuccess) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500294 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
295 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500296 }
297
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400298 fDecodingFrame.fIndex = frameToDecode;
299 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
300
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400301 using std::swap;
302 swap(fDecodingFrame, fDisplayFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400303 fDisplayFrame.fBitmap.notifyPixelsChanged();
Leon Scroggins III4c119452018-01-20 10:33:24 -0500304
305 if (animationEnded) {
306 return this->finish();
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400307 } else if (fCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF) {
308 // HEIF doesn't know the frame duration until after decoding. Update to
309 // the correct value. Note that earlier returns in this method either
310 // return kFinished, or fCurrentFrameDuration. If they return the
311 // latter, it is a frame that was previously decoded, so it has the
312 // updated value.
313 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
314 fCurrentFrameDuration = frameInfo.fDuration;
315 } else {
316 SkCodecPrintf("Failed to getFrameInfo on second attempt (HEIF)");
317 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500318 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500319 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500320}
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500321
322void SkAnimatedImage::onDraw(SkCanvas* canvas) {
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500323 // This SkBitmap may be reused later to decode the following frame. But Frame::init
324 // lazily copies the pixel ref if it has any other references. So it is safe to not
325 // do a deep copy here.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400326 auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
327 kNever_SkCopyPixelsMode);
328
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500329 if (fSimple) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400330 canvas->drawImage(image, 0, 0);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500331 return;
332 }
333
334 SkRect bounds = this->getBounds();
335 if (fPostProcess) {
336 canvas->saveLayer(&bounds, nullptr);
337 }
338 {
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400339 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500340 canvas->concat(fMatrix);
341 SkPaint paint;
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500342 paint.setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400343 canvas->drawImage(image, 0, 0, &paint);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500344 }
345 if (fPostProcess) {
346 canvas->drawPicture(fPostProcess);
347 canvas->restore();
348 }
349}
Leon Scroggins III4c119452018-01-20 10:33:24 -0500350
351void SkAnimatedImage::setRepetitionCount(int newCount) {
352 fRepetitionCount = newCount;
353}
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500354
355sk_sp<SkImage> SkAnimatedImage::getCurrentFrame() {
356 // This SkBitmap may be reused later to decode the following frame. But Frame::init
357 // lazily copies the pixel ref if it has any other references. So it is safe to not
358 // do a deep copy here.
359 return SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
360 kNever_SkCopyPixelsMode);
361}