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