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 31void 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 72bool 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 84void 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 96void 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 108void VirtualScreenImpl::InitBuffer() 109{ 110 currentPos = 0; 111 WriteBuffer(headStart); 112 WriteBuffer(orignalResolutionWidth); 113 WriteBuffer(orignalResolutionHeight); 114 WriteBuffer(compressionResolutionWidth); 115 WriteBuffer(compressionResolutionHeight); 116} 117 118void 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 159void 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 172void 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 181void 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 194void VirtualScreenImpl::FreeJpgMemory() 195{ 196 if (jpgScreenBuffer != nullptr) { 197 free(jpgScreenBuffer); 198 jpgScreenBuffer = NULL; 199 } 200} 201 202VirtualScreenImpl& VirtualScreenImpl::GetInstance() 203{ 204 static VirtualScreenImpl virtualScreen; 205 BaseGfxEngine::InitGfxEngine(&virtualScreen); 206 return virtualScreen; 207} 208 209void VirtualScreenImpl::CheckBufferSend() 210{ 211 VirtualScreenImpl::GetInstance().ScheduleBufferSend(); 212} 213 214VirtualScreenImpl::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 235VirtualScreenImpl::~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 249void 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 277OHOS::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 299uint16_t VirtualScreenImpl::GetScreenWidth() 300{ 301 return orignalResolutionWidth; 302} 303 304uint16_t VirtualScreenImpl::GetScreenHeight() 305{ 306 return orignalResolutionHeight; 307} 308