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