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