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 #include "base/log/ace_trace.h"
24 #include "base/log/log.h"
25 #include "base/memory/ace_type.h"
26 #include "core/components_ng/render/canvas_image.h"
27 #ifdef USE_ROSEN_DRAWING
28 #include "core/components_ng/render/drawing.h"
29 #endif
30 #include "core/image/image_provider.h"
31
32 namespace OHOS::Ace {
33
Pause()34 void AnimatedImagePlayer::Pause()
35 {
36 animator_->Pause();
37 }
38
Resume()39 void AnimatedImagePlayer::Resume()
40 {
41 animator_->Resume();
42 }
43
RenderFrame(const int32_t & index)44 void AnimatedImagePlayer::RenderFrame(const int32_t& index)
45 {
46 auto context = context_.Upgrade();
47 if (!context) {
48 LOGW("Context may be destroyed!");
49 return;
50 }
51 auto taskExecutor = context->GetTaskExecutor();
52 taskExecutor->PostTask(
53 [weak = AceType::WeakClaim(this), index, dstWidth = dstWidth_, dstHeight = dstHeight_, taskExecutor] {
54 ACE_SCOPED_TRACE("decode frame %d", index);
55 auto player = weak.Upgrade();
56 if (!player) {
57 return;
58 }
59
60 #ifndef USE_ROSEN_DRAWING
61 sk_sp<SkImage> skImage = player->DecodeFrameImage(index);
62 if (dstWidth > 0 && dstHeight > 0) {
63 skImage = ImageProvider::ApplySizeToSkImage(skImage, dstWidth, dstHeight);
64 }
65 if (!skImage) {
66 LOGW("animated player cannot get the %{public}d skImage!", index);
67 return;
68 }
69 auto canvasImage = NG::CanvasImage::Create(&skImage);
70 #else
71 std::shared_ptr<RSImage> dImage = player->DecodeFrameImage(index);
72 if (dstWidth > 0 && dstHeight > 0) {
73 dImage = ImageProvider::ApplySizeToDrawingImage(dImage, dstWidth, dstHeight);
74 }
75 if (!dImage) {
76 LOGW("animated player cannot get the %{public}d dImage!", index);
77 return;
78 }
79 auto canvasImage = NG::CanvasImage::Create(&dImage);
80 #endif
81 #ifdef PREVIEW
82 player->successCallback_(player->imageSource_, canvasImage);
83 },
84 TaskExecutor::TaskType::UI);
85 #else
86 taskExecutor->PostTask([callback = player->successCallback_, canvasImage,
87 source = player->imageSource_] { callback(source, canvasImage); },
88 TaskExecutor::TaskType::UI);
89 },
90 TaskExecutor::TaskType::IO);
91 #endif
92 }
93
94 #ifndef USE_ROSEN_DRAWING
DecodeFrameImage(const int32_t & index)95 sk_sp<SkImage> AnimatedImagePlayer::DecodeFrameImage(const int32_t& index)
96 {
97 // first seek in cache
98 auto iterator = cachedFrame_.find(index);
99 if (iterator != cachedFrame_.end() && iterator->second != nullptr) {
100 LOGD("index %{private}d found in cache.", index);
101 return SkImage::MakeFromBitmap(*iterator->second);
102 }
103
104 SkBitmap bitmap;
105 SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType);
106 bitmap.allocPixels(info);
107 SkCodec::Options options;
108 options.fFrameIndex = index;
109 const int32_t requiredFrame = frameInfos_[index].fRequiredFrame;
110 if (requiredFrame != SkCodec::kNoFrame) {
111 if (requiredFrame == lastRequiredFrameIndex_ && lastRequiredBitmap_ && lastRequiredBitmap_->getPixels() &&
112 CopyTo(&bitmap, lastRequiredBitmap_->colorType(), *lastRequiredBitmap_)) {
113 options.fPriorFrame = requiredFrame;
114 } else if (requiredFrame != lastRequiredFrameIndex_) {
115 // find requiredFrame in cached frame.
116 auto iter = cachedFrame_.find(requiredFrame);
117 if (iter != cachedFrame_.end() && iter->second != nullptr &&
118 CopyTo(&bitmap, iter->second->colorType(), *iter->second)) {
119 options.fPriorFrame = requiredFrame;
120 }
121 }
122 }
123
124 if (SkCodec::kSuccess != codec_->getPixels(info, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
125 LOGW("Could not getPixels for frame %{public}d:", index);
126 return nullptr;
127 }
128
129 if (frameInfos_[index].fDisposalMethod != SkCodecAnimation::DisposalMethod::kRestorePrevious) {
130 lastRequiredBitmap_ = std::make_unique<SkBitmap>(bitmap);
131 lastRequiredFrameIndex_ = index;
132 }
133
134 if (iterator != cachedFrame_.end() && iterator->second == nullptr) {
135 LOGD("index %{private}d cached.", index);
136 iterator->second = std::make_unique<SkBitmap>(bitmap);
137 }
138 return SkImage::MakeFromBitmap(bitmap);
139 }
140 #else
DecodeFrameImage(const int32_t & index)141 std::shared_ptr<RSImage> AnimatedImagePlayer::DecodeFrameImage(const int32_t& index)
142 {
143 LOGE("Drawing is not supported");
144 return std::make_shared<RSImage>();
145 }
146 #endif
147
CopyTo(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)148 bool AnimatedImagePlayer::CopyTo(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src)
149 {
150 SkPixmap srcPixmap;
151 if (!src.peekPixels(&srcPixmap)) {
152 return false;
153 }
154 SkBitmap tempDstBitmap;
155 SkImageInfo dstInfo = srcPixmap.info().makeColorType(dstColorType);
156 if (!tempDstBitmap.setInfo(dstInfo)) {
157 return false;
158 }
159 if (!tempDstBitmap.tryAllocPixels()) {
160 return false;
161 }
162 SkPixmap dstPixmap;
163 if (!tempDstBitmap.peekPixels(&dstPixmap)) {
164 return false;
165 }
166 if (!srcPixmap.readPixels(dstPixmap)) {
167 return false;
168 }
169 dst->swap(tempDstBitmap);
170 return true;
171 }
172
173 } // namespace OHOS::Ace
174