1 /*
2 * Copyright (c) 2023 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 "VirtualScreenImpl.h"
17
18 #include "draw/draw_utils.h"
19 #include "hal_tick.h"
20 #include "image_decode_ability.h"
21
22 #define boolean jpegboolean
23 #include "jpeglib.h"
24 #undef boolean
25 #include "task_manager.h"
26 #include "CommandParser.h"
27 #include "ModelManager.h"
28 #include "PreviewerEngineLog.h"
29 #include "TraceTool.h"
30
31 using namespace std;
32 using namespace std::chrono;
33
InitAll(std::string pipeName,std::string pipePort)34 void VirtualScreenImpl::InitAll(std::string pipeName, std::string pipePort)
35 {
36 OHOS::ImageDecodeAbility& ability = OHOS::ImageDecodeAbility::GetInstance();
37 ability.SetImageDecodeAbility(OHOS::IMG_SUPPORT_BITMAP | OHOS::IMG_SUPPORT_JPEG | OHOS::IMG_SUPPORT_PNG);
38 if (CommandParser::GetInstance().GetDeviceType() == "liteWearable") {
39 ability.SetImageDecodeAbility(OHOS::IMG_SUPPORT_BITMAP);
40 }
41
42 InitPipe(pipeName, pipePort);
43 if ((!CommandParser::GetInstance().IsResolutionValid(orignalResolutionWidth)) ||
44 (!CommandParser::GetInstance().IsResolutionValid(orignalResolutionHeight))) {
45 ELOG("VirtualScreen::InitAll invalid resolution, width : %d height : %d", orignalResolutionWidth,
46 orignalResolutionHeight);
47 return;
48 }
49
50 bufferSize = orignalResolutionWidth * orignalResolutionHeight * pixelSize + headSize;
51 wholeBuffer = new uint8_t[LWS_PRE + bufferSize];
52 regionWholeBuffer = new uint8_t[LWS_PRE + bufferSize];
53 screenBuffer = wholeBuffer + LWS_PRE;
54 regionBuffer = regionWholeBuffer + LWS_PRE;
55 osBuffer = new uint8_t[bufferSize];
56 if (screenBuffer == nullptr) {
57 ELOG("VirtualScreen::InitAll wholeBuffer memory allocation failed");
58 return;
59 }
60 InitBuffer();
61 }
62
IsRectValid(int32_t x1,int32_t y1,int32_t x2,int32_t y2) const63 bool VirtualScreenImpl::IsRectValid(int32_t x1, int32_t y1, int32_t x2, int32_t y2) const
64 {
65 if (x1 < 0 || y1 < 0) {
66 return false;
67 }
68
69 if (x2 >= orignalResolutionWidth || y2 >= orignalResolutionHeight) {
70 return false;
71 }
72 return true;
73 }
74
WriteRefreshRegion()75 void VirtualScreenImpl::WriteRefreshRegion()
76 {
77 currentPos = VERSION_POS;
78 WriteBuffer(protocolVersion);
79 WriteBuffer(regionX1);
80 WriteBuffer(regionY1);
81 regionWidth = static_cast<uint16_t>(orignalResolutionWidth);
82 WriteBuffer(regionWidth);
83 regionHeight = static_cast<uint16_t>(orignalResolutionHeight);
84 WriteBuffer(regionHeight);
85 }
86
UpdateRegion(int32_t x1,int32_t y1,int32_t x2,int32_t y2)87 void VirtualScreenImpl::UpdateRegion(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
88 {
89 regionX1 = x1;
90 regionY1 = y1;
91 regionX2 = (x2 < compressionResolutionWidth - extendPix)
92 ? (x2 + extendPix) : (compressionResolutionWidth - 1);
93 regionY2 = (y2 < compressionResolutionHeight - extendPix)
94 ? (y2 + extendPix) : (compressionResolutionHeight - 1);
95 regionWidth = regionX2 - regionX1 + 1;
96 regionHeight = regionY2 - regionY1 + 1;
97 }
98
InitBuffer()99 void VirtualScreenImpl::InitBuffer()
100 {
101 currentPos = 0;
102 WriteBuffer(headStart);
103 WriteBuffer(orignalResolutionWidth);
104 WriteBuffer(orignalResolutionHeight);
105 WriteBuffer(compressionResolutionWidth);
106 WriteBuffer(compressionResolutionHeight);
107 }
108
ScheduleBufferSend()109 void VirtualScreenImpl::ScheduleBufferSend()
110 {
111 if (!isChanged) {
112 return;
113 }
114
115 if (!isWebSocketConfiged) {
116 ELOG("image socket is not ready");
117 return;
118 }
119 isFrameUpdated = true;
120 if (CommandParser::GetInstance().IsRegionRefresh()) {
121 SendFullBuffer();
122 } else {
123 SendFullBuffer();
124 }
125 if (isFirstSend) {
126 ILOG("Send first buffer finish");
127 TraceTool::GetInstance().HandleTrace("Send first buffer finish");
128 isFirstSend = false;
129 }
130
131 {
132 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
133 if (!WebSocketServer::GetInstance().firstImageBuffer) {
134 WebSocketServer::GetInstance().firstImageBuffer = new uint8_t[LWS_PRE + bufferSize];
135 WebSocketServer::GetInstance().firstImagebufferSize = headSize + jpgBufferSize;
136 }
137 std::copy(regionBuffer,
138 regionBuffer + headSize + jpgBufferSize,
139 WebSocketServer::GetInstance().firstImageBuffer + LWS_PRE);
140 }
141
142 sendFrameCountPerMinute++;
143 isChanged = false;
144 }
145
Send(unsigned char * data,int32_t width,int32_t height)146 void VirtualScreenImpl::Send(unsigned char* data, int32_t width, int32_t height)
147 {
148 if (CommandParser::GetInstance().GetScreenMode() == CommandParser::ScreenMode::STATIC
149 && VirtualScreen::isOutOfSeconds) {
150 return;
151 }
152 // if websocket is config, use websocet, else use localsocket
153 VirtualScreen::RgbToJpg(data + headSize, width, height);
154 std::copy(jpgScreenBuffer, jpgScreenBuffer + jpgBufferSize, regionBuffer + headSize);
155 WebSocketServer::GetInstance().WriteData(regionBuffer, headSize + jpgBufferSize);
156 FreeJpgMemory();
157 }
158
SendFullBuffer()159 void VirtualScreenImpl::SendFullBuffer()
160 {
161 WriteRefreshRegion();
162 std::copy(screenBuffer, screenBuffer + headSize, regionBuffer);
163 Send(reinterpret_cast<unsigned char*>(screenBuffer),
164 compressionResolutionWidth,
165 compressionResolutionHeight);
166 }
167
SendRegionBuffer()168 void VirtualScreenImpl::SendRegionBuffer()
169 {
170 WriteRefreshRegion();
171 std::copy(screenBuffer, screenBuffer + headSize, regionBuffer);
172 for (int i = regionY1; i <= regionY2; ++i) {
173 uint8_t* startPos = screenBuffer + (i * compressionResolutionWidth + regionX1) * jpgPix + headSize;
174 std::copy(startPos,
175 startPos + regionWidth * jpgPix,
176 regionBuffer + ((i - regionY1) * regionWidth) * jpgPix + headSize);
177 }
178 Send(reinterpret_cast<unsigned char*>(regionBuffer), regionWidth, regionHeight);
179 }
180
FreeJpgMemory()181 void VirtualScreenImpl::FreeJpgMemory()
182 {
183 if (jpgScreenBuffer != nullptr) {
184 free(jpgScreenBuffer);
185 jpgScreenBuffer = NULL;
186 }
187 }
188
GetInstance()189 VirtualScreenImpl& VirtualScreenImpl::GetInstance()
190 {
191 static VirtualScreenImpl virtualScreen;
192 BaseGfxEngine::InitGfxEngine(&virtualScreen);
193 return virtualScreen;
194 }
195
CheckBufferSend()196 void VirtualScreenImpl::CheckBufferSend()
197 {
198 VirtualScreenImpl::GetInstance().ScheduleBufferSend();
199 }
200
VirtualScreenImpl()201 VirtualScreenImpl::VirtualScreenImpl()
202 : wholeBuffer(nullptr),
203 regionWholeBuffer(nullptr),
204 screenBuffer(nullptr),
205 regionBuffer(nullptr),
206 osBuffer(nullptr),
207 isChanged(false),
208 currentPos(0),
209 bufferSize(0),
210 isFirstRender(true),
211 isFirstSend(true),
212 regionX1(0),
213 regionY1(0),
214 regionX2(0),
215 regionY2(0),
216 regionWidth(0),
217 regionHeight(0),
218 bufferInfo(nullptr)
219 {
220 }
221
~VirtualScreenImpl()222 VirtualScreenImpl::~VirtualScreenImpl()
223 {
224 if (wholeBuffer != nullptr) {
225 delete [] wholeBuffer;
226 wholeBuffer = nullptr;
227 screenBuffer = nullptr;
228 }
229 FreeJpgMemory();
230 if (WebSocketServer::GetInstance().firstImageBuffer) {
231 delete [] WebSocketServer::GetInstance().firstImageBuffer;
232 WebSocketServer::GetInstance().firstImageBuffer = nullptr;
233 }
234 }
235
Flush(const OHOS::Rect & flushRect)236 void VirtualScreenImpl::Flush(const OHOS::Rect& flushRect)
237 {
238 if (isFirstRender) {
239 ILOG("Get first render buffer");
240 TraceTool::GetInstance().HandleTrace("Get first render buffer");
241 isFirstRender = false;
242 }
243
244 bool staticRet = VirtualScreen::JudgeStaticImage(SEND_IMG_DURATION_MS);
245 if (!staticRet) {
246 return;
247 }
248
249 for (int i = 0; i <= compressionResolutionHeight - 1; ++i) {
250 for (int j = 0; j <= compressionResolutionWidth - 1; ++j) {
251 uint8_t* curPixel = screenBuffer + (i * compressionResolutionWidth + j) * jpgPix + headSize;
252 uint8_t* osPixel = osBuffer + (i * compressionResolutionWidth + j) * pixelSize + headSize;
253 *(curPixel + redPos) = *(osPixel + bluePos);
254 *(curPixel + greenPos) = *(osPixel + greenPos);
255 *(curPixel + bluePos) = *(osPixel + redPos);
256 }
257 }
258
259 validFrameCountPerMinute++;
260 isChanged = true;
261 ScheduleBufferSend();
262 }
263
GetFBBufferInfo()264 OHOS::BufferInfo* VirtualScreenImpl::GetFBBufferInfo()
265 {
266 if (bufferInfo == nullptr) {
267 bufferInfo = new OHOS::BufferInfo;
268 bufferInfo->rect = {0, 0, compressionResolutionWidth - 1, compressionResolutionHeight - 1};
269 bufferInfo->mode = OHOS::ARGB8888;
270 bufferInfo->color = 0x44;
271 bufferInfo->phyAddr = bufferInfo->virAddr = osBuffer + headSize;
272 // 3: Shift right 3 bits
273 bufferInfo->stride = orignalResolutionWidth * (OHOS::DrawUtils::GetPxSizeByColorMode(bufferInfo->mode) >> 3);
274 bufferInfo->width = orignalResolutionWidth;
275 bufferInfo->height = orignalResolutionHeight;
276 }
277
278 return bufferInfo;
279 }
280
GetScreenWidth()281 uint16_t VirtualScreenImpl::GetScreenWidth()
282 {
283 return orignalResolutionWidth;
284 }
285
GetScreenHeight()286 uint16_t VirtualScreenImpl::GetScreenHeight()
287 {
288 return orignalResolutionHeight;
289 }
290