1 /*
2  * Copyright (c) 2024 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 #include "boot_picture_player.h"
16 
17 #include "event_handler.h"
18 #include "log.h"
19 #include "rs_trace.h"
20 #include "transaction/rs_interfaces.h"
21 
22 namespace OHOS {
23 namespace {
24     const std::string BOOT_PIC_ZIP = "/system/etc/graphic/bootpic.zip";
25 }
26 
BootPicturePlayer(const PlayerParams & params)27 BootPicturePlayer::BootPicturePlayer(const PlayerParams& params)
28 {
29     resPath_ = params.resPath;
30     rsSurface_ = params.rsSurface;
31     InitPicCoordinates(params.screenId);
32 }
33 
Play()34 void BootPicturePlayer::Play()
35 {
36     auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
37     while (receiver_ == nullptr) {
38         LOGI("receiver is nullptr, try create again");
39         receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", AppExecFwk::EventHandler::Current());
40     }
41 
42     VsyncError ret = receiver_->Init();
43     if (ret) {
44         LOGE("vsync receiver init failed: %{public}d", ret);
45         AppExecFwk::EventRunner::Current()->Stop();
46         return;
47     }
48 
49     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::preload");
50     if (ReadPicZipFile(imageVector_, freq_)) {
51         imgVecSize_ = static_cast<int32_t> (imageVector_.size());
52     } else {
53         LOGE("read pic zip failed");
54         AppExecFwk::EventRunner::Current()->Stop();
55         return;
56     }
57     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
58 
59     OHOS::Rosen::VSyncReceiver::FrameCallback fcb = {
60         .userData_ = this,
61         .callback_ = [this](int64_t, void*) { this->OnVsync(); },
62     };
63     int32_t changeFreq = static_cast<int32_t> (1000.0 / freq_ / 16);
64     ret = receiver_->SetVSyncRate(fcb, changeFreq);
65     if (ret) {
66         LOGE("SetVSyncRate failed: %{public}d %{public}d", ret, freq_);
67         AppExecFwk::EventRunner::Current()->Stop();
68         return;
69     } else {
70         LOGI("SetVSyncRate success: %{public}d, %{public}d", freq_, changeFreq);
71     }
72 }
73 
InitPicCoordinates(Rosen::ScreenId screenId)74 void BootPicturePlayer::InitPicCoordinates(Rosen::ScreenId screenId)
75 {
76     Rosen::RSInterfaces& interface = Rosen::RSInterfaces::GetInstance();
77     Rosen::RSScreenModeInfo modeinfo = interface.GetScreenActiveMode(screenId);
78     windowWidth_ = modeinfo.GetScreenWidth();
79     windowHeight_ = modeinfo.GetScreenHeight();
80     if (windowWidth_ >= windowHeight_) {
81         realHeight_ = windowHeight_;
82         realWidth_ = realHeight_;
83         pointX_ = (windowWidth_ - realWidth_) / NUMBER_TWO;
84     } else {
85         realWidth_ = windowWidth_;
86         realHeight_ = realWidth_;
87         pointY_ = (windowHeight_ - realHeight_) / NUMBER_TWO;
88     }
89 }
90 
ReadPicZipFile(ImageStructVec & imgVec,int32_t & freq)91 bool BootPicturePlayer::ReadPicZipFile(ImageStructVec& imgVec, int32_t& freq)
92 {
93     FrameRateConfig frameConfig;
94     ReadZipFile(GetPicZipPath(), imgVec, frameConfig);
95     int32_t imageNum = static_cast<int32_t>(imgVec.size());
96     if (imageNum < 0) {
97         LOGE("zip pic num is invalid.");
98         return false;
99     }
100 
101     SortZipFile(imgVec);
102 
103     if (CheckFrameRateValid(frameConfig.frameRate)) {
104         freq = frameConfig.frameRate;
105     } else {
106         LOGW("Only Support 30, 60 frame rate: %{public}d", frameConfig.frameRate);
107     }
108     LOGI("read freq: %{public}d, pic num: %{public}d", freq, imageNum);
109     return true;
110 }
111 
GetPicZipPath()112 std::string BootPicturePlayer::GetPicZipPath()
113 {
114     if (!IsFileExisted(resPath_)) {
115         LOGI("pic zip path empty or not exist, use default path");
116         return BOOT_PIC_ZIP;
117     }
118     return resPath_;
119 }
120 
CheckFrameRateValid(int32_t frameRate)121 bool BootPicturePlayer::CheckFrameRateValid(int32_t frameRate)
122 {
123     std::vector<int> freqs = {60, 30};
124     int nCount = std::count(freqs.begin(), freqs.end(), frameRate);
125     return nCount > 0;
126 }
127 
OnVsync()128 void BootPicturePlayer::OnVsync()
129 {
130     PostTask([this] { this->Draw(); });
131 }
132 
Draw()133 bool BootPicturePlayer::Draw()
134 {
135     if (picCurNo_ >= (imgVecSize_ - 1)) {
136         LOGI("play sequence frames end");
137         AppExecFwk::EventRunner::Current()->Stop();
138         return false;
139     }
140     picCurNo_ = picCurNo_ + 1;
141     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw RequestFrame");
142     auto frame = rsSurface_->RequestFrame(windowWidth_, windowHeight_);
143     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
144     if (frame == nullptr) {
145         LOGE("draw frame is nullptr");
146         AppExecFwk::EventRunner::Current()->Stop();
147         return false;
148     }
149 #ifdef NEW_RENDER_CONTEXT
150     if (rsSurface_ == nullptr) {
151         LOGE("rsSurface is nullptr");
152         AppExecFwk::EventRunner::Current()->Stop();
153         return false;
154     }
155     auto canvas = rsSurface_->GetCanvas();
156     OnDraw(canvas, picCurNo_);
157     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
158     rsSurface_->FlushFrame();
159     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
160 #else
161     rsSurfaceFrame_ = std::move(frame);
162     auto canvas = rsSurfaceFrame_->GetCanvas();
163     OnDraw(canvas, picCurNo_);
164     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
165     rsSurface_->FlushFrame(rsSurfaceFrame_);
166     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
167 #endif
168     return true;
169 }
170 
OnDraw(Rosen::Drawing::CoreCanvas * canvas,int32_t curNo)171 bool BootPicturePlayer::OnDraw(Rosen::Drawing::CoreCanvas* canvas, int32_t curNo)
172 {
173     if (canvas == nullptr) {
174         LOGE("OnDraw canvas is nullptr");
175         AppExecFwk::EventRunner::Current()->Stop();
176         return false;
177     }
178     if (curNo > (imgVecSize_ - 1) || curNo < 0) {
179         AppExecFwk::EventRunner::Current()->Stop();
180         return false;
181     }
182     std::shared_ptr<ImageStruct> imgstruct = imageVector_[curNo];
183     std::shared_ptr<Rosen::Drawing::Image> image = imgstruct->imageData;
184 
185     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawRect");
186     Rosen::Drawing::Brush brush;
187     brush.SetColor(Rosen::Drawing::Color::COLOR_BLACK);
188     Rosen::Drawing::Rect bgRect(0.0, 0.0, windowWidth_, windowHeight_);
189     canvas->AttachBrush(brush);
190     canvas->DrawRect(bgRect);
191     canvas->DetachBrush();
192     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
193     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawImageRect");
194     Rosen::Drawing::Rect rect(pointX_, pointY_, pointX_ + realWidth_, pointY_ + realHeight_);
195     Rosen::Drawing::SamplingOptions samplingOptions;
196     canvas->DrawImageRect(*image, rect, samplingOptions);
197     imageVector_[curNo].reset();
198     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
199     return true;
200 }
201 } // namespace OHOS
202