• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "third_party/skia/include/codec/SkCodecAnimation.h"
19 #include "third_party/skia/include/core/SkPixelRef.h"
20 
21 #include "base/log/log.h"
22 #include "core/components/image/flutter_render_image.h"
23 #include "core/image/image_provider.h"
24 
25 namespace OHOS::Ace {
26 
Pause()27 void AnimatedImagePlayer::Pause()
28 {
29     animator_->Pause();
30 }
31 
Resume()32 void AnimatedImagePlayer::Resume()
33 {
34     animator_->Resume();
35 }
36 
RenderFrame(const int32_t & index)37 void AnimatedImagePlayer::RenderFrame(const int32_t& index)
38 {
39     auto context = context_.Upgrade();
40     if (!context) {
41         LOGW("Context may be destroyed!");
42         return;
43     }
44     auto taskExecutor = context->GetTaskExecutor();
45     taskExecutor->PostTask(
46         [weak = AceType::WeakClaim(this), index, dstWidth = dstWidth_, dstHeight = dstHeight_, taskExecutor] {
47             auto player = weak.Upgrade();
48             if (!player) {
49                 return;
50             }
51             auto canvasImage = flutter::CanvasImage::Create();
52             sk_sp<SkImage> skImage = player->DecodeFrameImage(index);
53             if (dstWidth > 0 && dstHeight > 0) {
54                 skImage = ImageProvider::ApplySizeToSkImage(skImage, dstWidth, dstHeight);
55             }
56             if (skImage) {
57                 canvasImage->set_image({ skImage, player->unrefQueue_ });
58             } else {
59                 LOGW("animated player cannot get the %{public}d skImage!", index);
60                 return;
61             }
62 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
63             player->successCallback_(player->imageSource_, canvasImage);
64         },
65         TaskExecutor::TaskType::UI);
66 #else
67             taskExecutor->PostTask([callback = player->successCallback_, canvasImage,
68                                        source = player->imageSource_] { callback(source, canvasImage); },
69                 TaskExecutor::TaskType::UI);
70         },
71         TaskExecutor::TaskType::IO);
72 #endif
73 
74 }
75 
DecodeFrameImage(const int32_t & index)76 sk_sp<SkImage> AnimatedImagePlayer::DecodeFrameImage(const int32_t& index)
77 {
78     // first seek in cache
79     auto iterator = cachedFrame_.find(index);
80     if (iterator != cachedFrame_.end() && iterator->second != nullptr) {
81         LOGD("index %{private}d found in cache.", index);
82         return SkImage::MakeFromBitmap(*iterator->second);
83     }
84 
85     SkBitmap bitmap;
86     SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType);
87     bitmap.allocPixels(info);
88     SkCodec::Options options;
89     options.fFrameIndex = index;
90     const int32_t requiredFrame = frameInfos_[index].fRequiredFrame;
91     if (requiredFrame != SkCodec::kNoFrame) {
92         if (requiredFrame == lastRequiredFrameIndex_ && lastRequiredBitmap_ && lastRequiredBitmap_->getPixels() &&
93             CopyTo(&bitmap, lastRequiredBitmap_->colorType(), *lastRequiredBitmap_)) {
94             options.fPriorFrame = requiredFrame;
95         } else if (requiredFrame != lastRequiredFrameIndex_) {
96             // find requiredFrame in cached frame.
97             auto iter = cachedFrame_.find(requiredFrame);
98             if (iter != cachedFrame_.end() && iter->second != nullptr &&
99                 CopyTo(&bitmap, iter->second->colorType(), *iter->second)) {
100                 options.fPriorFrame = requiredFrame;
101             }
102         }
103     }
104 
105     if (SkCodec::kSuccess != codec_->getPixels(info, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
106         LOGW("Could not getPixels for frame %{public}d:", index);
107         return nullptr;
108     }
109 
110     if (frameInfos_[index].fDisposalMethod != SkCodecAnimation::DisposalMethod::kRestorePrevious) {
111         lastRequiredBitmap_ = std::make_unique<SkBitmap>(bitmap);
112         lastRequiredFrameIndex_ = index;
113     }
114 
115     if (iterator != cachedFrame_.end() && iterator->second == nullptr) {
116         LOGD("index %{private}d cached.", index);
117         iterator->second = std::make_unique<SkBitmap>(bitmap);
118     }
119 #ifndef GPU_DISABLED
120 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
121     // weak reference of io manager must be check and used on io thread, because io manager is created on io thread.
122     if (ioManager_) {
123         auto resourceContext = ioManager_->GetResourceContext();
124         if (resourceContext) {
125             SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(), bitmap.pixelRef()->rowBytes());
126             return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), pixmap, true, pixmap.colorSpace());
127         }
128     }
129 #endif
130 #endif
131     return SkImage::MakeFromBitmap(bitmap);
132 }
133 
CopyTo(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)134 bool AnimatedImagePlayer::CopyTo(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src)
135 {
136     SkPixmap srcPixmap;
137     if (!src.peekPixels(&srcPixmap)) {
138         return false;
139     }
140     SkBitmap tempDstBitmap;
141     SkImageInfo dstInfo = srcPixmap.info().makeColorType(dstColorType);
142     if (!tempDstBitmap.setInfo(dstInfo)) {
143         return false;
144     }
145     if (!tempDstBitmap.tryAllocPixels()) {
146         return false;
147     }
148     SkPixmap dstPixmap;
149     if (!tempDstBitmap.peekPixels(&dstPixmap)) {
150         return false;
151     }
152     if (!srcPixmap.readPixels(dstPixmap)) {
153         return false;
154     }
155     dst->swap(tempDstBitmap);
156     return true;
157 }
158 
159 } // namespace OHOS::Ace
160