1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/image/animated_image_player.h"
17
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/codec/SkCodecAnimation.h"
20 #include "include/core/SkPixelRef.h"
21 #endif
22
23 #ifdef USE_ROSEN_DRAWING
24 #include "core/components_ng/render/drawing.h"
25 #include "drawing/engine_adapter/skia_adapter/skia_image_info.h"
26 #endif
27
28 namespace OHOS::Ace {
29
Pause()30 void AnimatedImagePlayer::Pause()
31 {
32 animator_->Pause();
33 }
34
Resume()35 void AnimatedImagePlayer::Resume()
36 {
37 animator_->Resume();
38 }
39
RenderFrame(const int32_t & index)40 void AnimatedImagePlayer::RenderFrame(const int32_t& index)
41 {
42 auto context = context_.Upgrade();
43 if (!context) {
44 LOGW("Context may be destroyed!");
45 return;
46 }
47 auto taskExecutor = context->GetTaskExecutor();
48 taskExecutor->PostTask(
49 [weak = AceType::WeakClaim(this), index, dstWidth = dstWidth_, dstHeight = dstHeight_, taskExecutor] {
50 ACE_SCOPED_TRACE("decode frame %d", index);
51 auto player = weak.Upgrade();
52 if (!player) {
53 return;
54 }
55
56 #ifndef USE_ROSEN_DRAWING
57 sk_sp<SkImage> skImage = player->DecodeFrameImage(index);
58 if (dstWidth > 0 && dstHeight > 0) {
59 skImage = ImageProvider::ApplySizeToSkImage(skImage, dstWidth, dstHeight);
60 }
61 if (!skImage) {
62 LOGW("animated player cannot get the %{public}d skImage!", index);
63 return;
64 }
65 auto canvasImage = NG::CanvasImage::Create(&skImage);
66 #else
67 std::shared_ptr<RSImage> dImage = player->DecodeFrameImage(index);
68 if (dstWidth > 0 && dstHeight > 0) {
69 dImage = ImageProvider::ApplySizeToDrawingImage(dImage, dstWidth, dstHeight);
70 }
71 if (!dImage) {
72 LOGW("animated player cannot get the %{public}d dImage!", index);
73 return;
74 }
75 auto canvasImage = NG::CanvasImage::Create(&dImage);
76 #endif
77 #ifdef PREVIEW
78 player->successCallback_(player->imageSource_, canvasImage);
79 },
80 TaskExecutor::TaskType::UI, "ArkUIImagePlayerRenderAnimatedFrame");
81 #else
82 taskExecutor->PostTask([callback = player->successCallback_, canvasImage,
83 source = player->imageSource_] { callback(source, canvasImage); },
84 TaskExecutor::TaskType::UI, "ArkUIImageRenderAnimatedFrameSuccess");
85 },
86 TaskExecutor::TaskType::IO, "ArkUIImagePlayerRenderAnimatedFrame");
87 #endif
88 }
89
90 #ifndef USE_ROSEN_DRAWING
DecodeFrameImage(const int32_t & index)91 sk_sp<SkImage> AnimatedImagePlayer::DecodeFrameImage(const int32_t& index)
92 {
93 // first seek in cache
94 auto iterator = cachedFrame_.find(index);
95 if (iterator != cachedFrame_.end() && iterator->second != nullptr) {
96 return SkImage::MakeFromBitmap(*iterator->second);
97 }
98
99 SkBitmap bitmap;
100 SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType);
101 bitmap.allocPixels(info);
102 SkCodec::Options options;
103 options.fFrameIndex = index;
104 const int32_t requiredFrame = frameInfos_[index].fRequiredFrame;
105 if (requiredFrame != SkCodec::kNoFrame) {
106 if (requiredFrame == lastRequiredFrameIndex_ && lastRequiredBitmap_ && lastRequiredBitmap_->getPixels() &&
107 CopyTo(&bitmap, lastRequiredBitmap_->colorType(), *lastRequiredBitmap_)) {
108 options.fPriorFrame = requiredFrame;
109 } else if (requiredFrame != lastRequiredFrameIndex_) {
110 // find requiredFrame in cached frame.
111 auto iter = cachedFrame_.find(requiredFrame);
112 if (iter != cachedFrame_.end() && iter->second != nullptr &&
113 CopyTo(&bitmap, iter->second->colorType(), *iter->second)) {
114 options.fPriorFrame = requiredFrame;
115 }
116 }
117 }
118
119 if (SkCodec::kSuccess != codec_->getPixels(info, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
120 LOGW("Could not getPixels for frame %{public}d:", index);
121 return nullptr;
122 }
123
124 if (frameInfos_[index].fDisposalMethod != SkCodecAnimation::DisposalMethod::kRestorePrevious) {
125 lastRequiredBitmap_ = std::make_unique<SkBitmap>(bitmap);
126 lastRequiredFrameIndex_ = index;
127 }
128
129 if (iterator != cachedFrame_.end() && iterator->second == nullptr) {
130 iterator->second = std::make_unique<SkBitmap>(bitmap);
131 }
132 return SkImage::MakeFromBitmap(bitmap);
133 }
134
CopyTo(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)135 bool AnimatedImagePlayer::CopyTo(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src)
136 {
137 SkPixmap srcPixmap;
138 if (!src.peekPixels(&srcPixmap)) {
139 return false;
140 }
141 SkBitmap tempDstBitmap;
142 SkImageInfo dstInfo = srcPixmap.info().makeColorType(dstColorType);
143 if (!tempDstBitmap.setInfo(dstInfo)) {
144 return false;
145 }
146 if (!tempDstBitmap.tryAllocPixels()) {
147 return false;
148 }
149 SkPixmap dstPixmap;
150 if (!tempDstBitmap.peekPixels(&dstPixmap)) {
151 return false;
152 }
153 if (!srcPixmap.readPixels(dstPixmap)) {
154 return false;
155 }
156 dst->swap(tempDstBitmap);
157 return true;
158 }
159 #else
DecodeFrameImage(const int32_t & index)160 std::shared_ptr<RSImage> AnimatedImagePlayer::DecodeFrameImage(const int32_t& index)
161 {
162 // first seek in cache
163 auto iterator = cachedFrame_.find(index);
164 if (iterator != cachedFrame_.end() && iterator->second != nullptr) {
165 auto image = std::shared_ptr<RSImage>();
166 if (!image) {
167 return nullptr;
168 }
169 image->BuildFromBitmap(*iterator->second);
170 return image;
171 }
172
173 RSBitmap bitmap;
174 SkImageInfo skImageInfo = codec_->getInfo().makeColorType(kN32_SkColorType);
175 auto imageInfo = Rosen::Drawing::SkiaImageInfo::ConvertToRSImageInfo(skImageInfo);
176 bitmap.Build(imageInfo);
177 SkCodec::Options options;
178 options.fFrameIndex = index;
179 const int32_t requiredFrame = frameInfos_[index].fRequiredFrame;
180 if (requiredFrame != SkCodec::kNoFrame) {
181 if (requiredFrame == lastRequiredFrameIndex_ && lastRequiredBitmap_ && lastRequiredBitmap_->GetPixels() &&
182 CopyTo(&bitmap, *lastRequiredBitmap_)) {
183 options.fPriorFrame = requiredFrame;
184 } else if (requiredFrame != lastRequiredFrameIndex_) {
185 // find requiredFrame in cached frame.
186 auto iter = cachedFrame_.find(requiredFrame);
187 if (iter != cachedFrame_.end() && iter->second != nullptr &&
188 CopyTo(&bitmap, *iter->second)) {
189 options.fPriorFrame = requiredFrame;
190 }
191 }
192 }
193
194 if (SkCodec::kSuccess != codec_->getPixels(skImageInfo, bitmap.GetPixels(), bitmap.GetRowBytes(), &options)) {
195 LOGW("Could not getPixels for frame %{public}d:", index);
196 return nullptr;
197 }
198
199 if (frameInfos_[index].fDisposalMethod != SkCodecAnimation::DisposalMethod::kRestorePrevious) {
200 lastRequiredBitmap_ = std::make_unique<RSBitmap>(bitmap);
201 lastRequiredFrameIndex_ = index;
202 }
203
204 if (iterator != cachedFrame_.end() && iterator->second == nullptr) {
205 iterator->second = std::make_unique<RSBitmap>(bitmap);
206 }
207 auto image = std::make_shared<RSImage>();
208 if (!image) {
209 return nullptr;
210 }
211 image->BuildFromBitmap(bitmap);
212 return image;
213 }
214
CopyTo(RSBitmap * dst,const RSBitmap & src)215 bool AnimatedImagePlayer::CopyTo(RSBitmap* dst, const RSBitmap& src)
216 {
217 auto info = src.GetImageInfo();
218 dst->Build(info);
219 src.CopyPixels(*dst, 0, 0);
220 return true;
221 }
222 #endif
223
224 } // namespace OHOS::Ace
225