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