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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_ANIMATED_IMAGE_PLAYER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_ANIMATED_IMAGE_PLAYER_H
18 
19 #include <unordered_map>
20 
21 #include "include/codec/SkCodec.h"
22 
23 #include "base/memory/ace_type.h"
24 #include "core/animation/animator.h"
25 #include "core/animation/picture_animation.h"
26 #include "core/image/image_provider.h"
27 #include "core/image/image_source_info.h"
28 #include "core/pipeline/pipeline_base.h"
29 
30 namespace OHOS::Ace {
31 
32 class AnimatedImagePlayer : public virtual AceType {
33     DECLARE_ACE_TYPE(AnimatedImagePlayer, AceType);
34 
35 public:
36     AnimatedImagePlayer(ImageSourceInfo source, UploadSuccessCallback successCallback,
37         const WeakPtr<PipelineBase>& weakContext, std::unique_ptr<SkCodec> codec, int32_t dstWidth = -1,
38         int32_t dstHeight = -1)
39         : imageSource_(source), successCallback_(successCallback), context_(weakContext), codec_(std::move(codec)),
40           frameCount_(codec_->getFrameCount()), repetitionCount_(codec_->getRepetitionCount()),
41           frameInfos_(codec_->getFrameInfo()), dstWidth_(dstWidth), dstHeight_(dstHeight)
42     {
43         auto context = context_.Upgrade();
44         if (context) {
45             animator_ = CREATE_ANIMATOR(context);
46             auto pictureAnimation = AceType::MakeRefPtr<PictureAnimation<int32_t>>();
47             float totalFrameDuration = 0.0f;
48             int32_t lastRequiredIndex = -1;
49             for (int32_t index = 0; index < frameCount_; index++) {
50                 // if frame duration is 0, set this frame duration as 100ms
51                 if (frameInfos_[index].fDuration <= 0) {
52                     frameInfos_[index].fDuration = 100;
53                 }
54                 totalFrameDuration += frameInfos_[index].fDuration;
55 
56                 // process required frame index.
57                 int32_t requiredIndex = frameInfos_[index].fRequiredFrame;
58                 // if requiredIndex is valid
59                 if (requiredIndex >= 0 && requiredIndex < frameCount_) {
60                     // if require prior frame before last frame, cache it after first loop.
61                     if (requiredIndex < lastRequiredIndex) {
62                         cachedFrame_.emplace(requiredIndex, nullptr);
63                     }
64                     lastRequiredIndex = requiredIndex;
65                 }
66             }
67             for (int32_t index = 0; index < frameCount_; index++) {
68                 pictureAnimation->AddPicture(
69                     static_cast<float>(frameInfos_[index].fDuration) / totalFrameDuration, index);
70             }
71             pictureAnimation->AddListener([weak = WeakClaim(this)](const int32_t& index) {
72                 auto player = weak.Upgrade();
73                 if (player) {
74                     player->RenderFrame(index);
75                 }
76             });
77             animator_->AddInterpolator(pictureAnimation);
78             animator_->SetDuration(totalFrameDuration);
79             auto repetitionCount = context->IsJsCard() ? 1 : repetitionCount_;
80             animator_->SetIteration(repetitionCount > 0 ? repetitionCount : ANIMATION_REPEAT_INFINITE);
81             animator_->Play();
82         }
83     }
84 
85     ~AnimatedImagePlayer() override = default;
86 
87     void Pause();
88     void Resume();
89     void RenderFrame(const int32_t& index);
90 
SetTargetSize(int32_t width,int32_t height)91     void SetTargetSize(int32_t width, int32_t height)
92     {
93         dstWidth_ = width;
94         dstHeight_ = height;
95     }
96 
97 private:
98 #ifndef USE_ROSEN_DRAWING
99     sk_sp<SkImage> DecodeFrameImage(const int32_t& index);
100     static bool CopyTo(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src);
101 #else
102     std::shared_ptr<RSImage> DecodeFrameImage(const int32_t& index);
103     static bool CopyTo(RSBitmap* dst, const RSBitmap& src);
104 #endif
105 
106     ImageSourceInfo imageSource_;
107     UploadSuccessCallback successCallback_;
108     WeakPtr<PipelineBase> context_;
109 
110     const std::unique_ptr<SkCodec> codec_;
111     const int32_t frameCount_;
112     const int32_t repetitionCount_;
113     std::vector<SkCodec::FrameInfo> frameInfos_;
114 
115     RefPtr<Animator> animator_;
116     int32_t dstWidth_ = -1;
117     int32_t dstHeight_ = -1;
118 
119 #ifndef USE_ROSEN_DRAWING
120     // used to cache required frame.
121     std::unordered_map<int32_t, std::unique_ptr<SkBitmap>> cachedFrame_;
122 
123     // used to cache last required frame. this will be reset during looping.
124     std::unique_ptr<SkBitmap> lastRequiredBitmap_;
125 #else
126     // used to cache required frame.
127     std::unordered_map<int32_t, std::unique_ptr<RSBitmap>> cachedFrame_;
128 
129     // used to cache last required frame. this will be reset during looping.
130     std::unique_ptr<RSBitmap> lastRequiredBitmap_;
131 #endif
132     int32_t lastRequiredFrameIndex_ = -1;
133 };
134 
135 } // namespace OHOS::Ace
136 
137 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_ANIMATED_IMAGE_PLAYER_H
138