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