blob: 6db6afde4a64b4c83f67052e768f4c139bed5195 [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,
22 SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050023 if (!codec) {
24 return nullptr;
25 }
Brian Salomon9241a6d2019-10-03 13:26:54 -040026 auto info = codec->getInfo().makeDimensions(scaledSize);
Leon Scroggins III85463352019-02-04 15:22:10 -050027 return Make(std::move(codec), info, cropRect, std::move(postProcess));
28}
Leon Scroggins III7a10b332018-01-12 11:24:30 -050029
Leon Scroggins III85463352019-02-04 15:22:10 -050030sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
31 const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
32 if (!codec) {
33 return nullptr;
34 }
35
36 auto scaledSize = requestedInfo.dimensions();
37 auto decodeInfo = requestedInfo;
38 if (codec->getEncodedFormat() != SkEncodedImageFormat::kWEBP
39 || scaledSize.width() >= decodeInfo.width()
40 || scaledSize.height() >= decodeInfo.height()) {
41 // Only libwebp can decode to arbitrary smaller sizes.
42 auto dims = codec->getInfo().dimensions();
Brian Salomon9241a6d2019-10-03 13:26:54 -040043 decodeInfo = decodeInfo.makeDimensions(dims);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050044 }
45
46 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
47 decodeInfo, cropRect, std::move(postProcess)));
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040048 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050049 // tryAllocPixels failed.
50 return nullptr;
51 }
52
53 return image;
54}
55
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050056sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
57 if (!codec) {
58 return nullptr;
59 }
60
61 const auto decodeInfo = codec->getInfo();
62 const auto scaledSize = decodeInfo.dimensions();
63 const auto cropRect = SkIRect::MakeSize(scaledSize);
64 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
65 decodeInfo, cropRect, nullptr));
66
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040067 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050068 // tryAllocPixels failed.
69 return nullptr;
70 }
71
72 SkASSERT(image->fSimple);
73 return image;
74}
75
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050076SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
77 SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050078 : fCodec(std::move(codec))
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050079 , fScaledSize(scaledSize)
80 , fDecodeInfo(decodeInfo)
81 , fCropRect(cropRect)
82 , fPostProcess(std::move(postProcess))
Leon Scroggins III4c119452018-01-20 10:33:24 -050083 , fFrameCount(fCodec->codec()->getFrameCount())
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050084 , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess
85 && fCropRect == fDecodeInfo.bounds())
Leon Scroggins III7a10b332018-01-12 11:24:30 -050086 , fFinished(false)
Leon Scroggins III4c119452018-01-20 10:33:24 -050087 , fRepetitionCount(fCodec->codec()->getRepetitionCount())
88 , fRepetitionsCompleted(0)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050089{
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040090 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050091 return;
92 }
93
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050094 if (!fSimple) {
95 fMatrix = SkMatrix::MakeTrans(-fCropRect.fLeft, -fCropRect.fTop);
96 float scaleX = (float) fScaledSize.width() / fDecodeInfo.width();
97 float scaleY = (float) fScaledSize.height() / fDecodeInfo.height();
98 fMatrix.preConcat(SkMatrix::MakeScale(scaleX, scaleY));
99 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500100 this->decodeNextFrame();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500101}
102
103SkAnimatedImage::~SkAnimatedImage() { }
104
105SkRect SkAnimatedImage::onGetBounds() {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500106 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500107}
108
109SkAnimatedImage::Frame::Frame()
Nigel Tao66bc5242018-08-22 10:56:03 +1000110 : fIndex(SkCodec::kNoFrame)
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500111{}
112
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400113bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) {
114 if (fBitmap.getPixels()) {
115 if (fBitmap.pixelRef()->unique()) {
116 SkAssertResult(fBitmap.setAlphaType(info.alphaType()));
117 return true;
118 }
119
120 // An SkCanvas provided to onDraw is still holding a reference.
121 // Copy before we decode to ensure that we don't overwrite the
122 // expected contents of the image.
123 if (OnInit::kRestoreIfNecessary == onInit) {
124 SkBitmap tmp;
125 if (!tmp.tryAllocPixels(info)) {
126 return false;
127 }
128
129 memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400130 using std::swap;
131 swap(tmp, fBitmap);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400132 return true;
133 }
134 }
135
136 return fBitmap.tryAllocPixels(info);
137}
138
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500139bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400140 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500141 return false;
142 }
143
144 memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
145 dst->fIndex = fIndex;
146 dst->fDisposalMethod = fDisposalMethod;
147 return true;
148}
149
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500150void SkAnimatedImage::reset() {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500151 fFinished = false;
152 fRepetitionsCompleted = 0;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400153 if (fDisplayFrame.fIndex != 0) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000154 fDisplayFrame.fIndex = SkCodec::kNoFrame;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400155 this->decodeNextFrame();
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500156 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500157}
158
159static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
160 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
161}
162
Leon Scroggins III4c119452018-01-20 10:33:24 -0500163int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
164 SkASSERT(animationEnded != nullptr);
165 *animationEnded = false;
166
167 const int frameToDecode = current + 1;
168 if (frameToDecode == fFrameCount - 1) {
169 // Final frame. Check to determine whether to stop.
170 fRepetitionsCompleted++;
171 if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
172 && fRepetitionsCompleted > fRepetitionCount) {
173 *animationEnded = true;
174 }
175 } else if (frameToDecode == fFrameCount) {
176 return 0;
177 }
178 return frameToDecode;
179}
180
181double SkAnimatedImage::finish() {
182 fFinished = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500183 fCurrentFrameDuration = kFinished;
184 return kFinished;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500185}
186
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500187int SkAnimatedImage::decodeNextFrame() {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500188 if (fFinished) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500189 return kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500190 }
191
Leon Scroggins III4c119452018-01-20 10:33:24 -0500192 bool animationEnded = false;
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400193 const int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500194
195 SkCodec::FrameInfo frameInfo;
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500196 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500197 if (!frameInfo.fFullyReceived) {
198 SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500199 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500200 }
201
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500202 fCurrentFrameDuration = frameInfo.fDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500203 } else {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500204 animationEnded = true;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500205 if (0 == frameToDecode) {
206 // Static image. This is okay.
Nigel Tao66bc5242018-08-22 10:56:03 +1000207 frameInfo.fRequiredFrame = SkCodec::kNoFrame;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500208 frameInfo.fAlphaType = fCodec->getInfo().alphaType();
Kevin Lubick289d36f2018-02-13 10:25:00 -0500209 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500210 // These fields won't be read.
211 frameInfo.fDuration = INT_MAX;
212 frameInfo.fFullyReceived = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500213 fCurrentFrameDuration = kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500214 } else {
215 SkCodecPrintf("Error getting frameInfo for frame %i\n",
216 frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500217 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500218 }
219 }
220
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400221 if (frameToDecode == fDisplayFrame.fIndex) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500222 if (animationEnded) {
223 return this->finish();
224 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500225 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500226 }
227
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400228 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
229 if (frameToDecode == frame->fIndex) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400230 using std::swap;
231 swap(fDisplayFrame, *frame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400232 if (animationEnded) {
233 return this->finish();
234 }
235 return fCurrentFrameDuration;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500236 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500237 }
238
239 // The following code makes an effort to avoid overwriting a frame that will
240 // be used again. If frame |i| is_restore_previous, frame |i+1| will not
241 // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
242 // for frame |i+1|.
243 // We could be even smarter about which frames to save by looking at the
244 // entire dependency chain.
245 SkCodec::Options options;
246 options.fFrameIndex = frameToDecode;
Nigel Tao66bc5242018-08-22 10:56:03 +1000247 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500248 if (is_restore_previous(frameInfo.fDisposalMethod)) {
249 // frameToDecode will be discarded immediately after drawing, so
250 // do not overwrite a frame which could possibly be used in the
251 // future.
Nigel Tao66bc5242018-08-22 10:56:03 +1000252 if (fDecodingFrame.fIndex != SkCodec::kNoFrame &&
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400253 !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400254 using std::swap;
255 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500256 }
257 }
258 } else {
259 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000260 if (SkCodec::kNoFrame == frame.fIndex ||
261 is_restore_previous(frame.fDisposalMethod)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500262 return false;
263 }
264
265 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
266 };
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400267 if (validPriorFrame(fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500268 if (is_restore_previous(frameInfo.fDisposalMethod)) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400269 // fDecodingFrame is a good frame to use for this one, but we
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500270 // don't want to overwrite it.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400271 fDecodingFrame.copyTo(&fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500272 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400273 options.fPriorFrame = fDecodingFrame.fIndex;
274 } else if (validPriorFrame(fDisplayFrame)) {
275 if (!fDisplayFrame.copyTo(&fDecodingFrame)) {
276 SkCodecPrintf("Failed to allocate pixels for frame\n");
277 return this->finish();
278 }
279 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500280 } else if (validPriorFrame(fRestoreFrame)) {
281 if (!is_restore_previous(frameInfo.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400282 using std::swap;
283 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400284 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500285 SkCodecPrintf("Failed to restore frame\n");
Leon Scroggins III4c119452018-01-20 10:33:24 -0500286 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500287 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400288 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500289 }
290 }
291
292 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
293 kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400294 auto info = fDecodeInfo.makeAlphaType(alphaType);
295 SkBitmap* dst = &fDecodingFrame.fBitmap;
296 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
297 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500298 }
299
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500300 auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
301 &options);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500302 if (result != SkCodec::kSuccess) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500303 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
304 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500305 }
306
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400307 fDecodingFrame.fIndex = frameToDecode;
308 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
309
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400310 using std::swap;
311 swap(fDecodingFrame, fDisplayFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400312 fDisplayFrame.fBitmap.notifyPixelsChanged();
Leon Scroggins III4c119452018-01-20 10:33:24 -0500313
314 if (animationEnded) {
315 return this->finish();
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400316 } else if (fCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF) {
317 // HEIF doesn't know the frame duration until after decoding. Update to
318 // the correct value. Note that earlier returns in this method either
319 // return kFinished, or fCurrentFrameDuration. If they return the
320 // latter, it is a frame that was previously decoded, so it has the
321 // updated value.
322 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
323 fCurrentFrameDuration = frameInfo.fDuration;
324 } else {
325 SkCodecPrintf("Failed to getFrameInfo on second attempt (HEIF)");
326 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500327 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500328 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500329}
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500330
331void SkAnimatedImage::onDraw(SkCanvas* canvas) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400332 auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
333 kNever_SkCopyPixelsMode);
334
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500335 if (fSimple) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400336 canvas->drawImage(image, 0, 0);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500337 return;
338 }
339
340 SkRect bounds = this->getBounds();
341 if (fPostProcess) {
342 canvas->saveLayer(&bounds, nullptr);
343 }
344 {
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400345 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500346 canvas->concat(fMatrix);
347 SkPaint paint;
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500348 paint.setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400349 canvas->drawImage(image, 0, 0, &paint);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500350 }
351 if (fPostProcess) {
352 canvas->drawPicture(fPostProcess);
353 canvas->restore();
354 }
355}
Leon Scroggins III4c119452018-01-20 10:33:24 -0500356
357void SkAnimatedImage::setRepetitionCount(int newCount) {
358 fRepetitionCount = newCount;
359}