17c804472Sopenharmony_ci/*
27c804472Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
37c804472Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
47c804472Sopenharmony_ci * you may not use this file except in compliance with the License.
57c804472Sopenharmony_ci * You may obtain a copy of the License at
67c804472Sopenharmony_ci *
77c804472Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
87c804472Sopenharmony_ci *
97c804472Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
107c804472Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
117c804472Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127c804472Sopenharmony_ci * See the License for the specific language governing permissions and
137c804472Sopenharmony_ci * limitations under the License.
147c804472Sopenharmony_ci */
157c804472Sopenharmony_ci
167c804472Sopenharmony_ci#include "VirtualScreenImpl.h"
177c804472Sopenharmony_ci
187c804472Sopenharmony_ci#include "draw/draw_utils.h"
197c804472Sopenharmony_ci#include "hal_tick.h"
207c804472Sopenharmony_ci#include "image_decode_ability.h"
217c804472Sopenharmony_ci
227c804472Sopenharmony_ci#define boolean jpegboolean
237c804472Sopenharmony_ci#include "jpeglib.h"
247c804472Sopenharmony_ci#undef boolean
257c804472Sopenharmony_ci#include "task_manager.h"
267c804472Sopenharmony_ci#include "CommandParser.h"
277c804472Sopenharmony_ci#include "ModelManager.h"
287c804472Sopenharmony_ci#include "PreviewerEngineLog.h"
297c804472Sopenharmony_ci#include "TraceTool.h"
307c804472Sopenharmony_ci
317c804472Sopenharmony_civoid VirtualScreenImpl::InitAll(std::string pipeName, std::string pipePort)
327c804472Sopenharmony_ci{
337c804472Sopenharmony_ci    OHOS::ImageDecodeAbility& ability = OHOS::ImageDecodeAbility::GetInstance();
347c804472Sopenharmony_ci    ability.SetImageDecodeAbility(OHOS::IMG_SUPPORT_BITMAP | OHOS::IMG_SUPPORT_JPEG | OHOS::IMG_SUPPORT_PNG);
357c804472Sopenharmony_ci    if (CommandParser::GetInstance().GetDeviceType() == "liteWearable") {
367c804472Sopenharmony_ci        ability.SetImageDecodeAbility(OHOS::IMG_SUPPORT_BITMAP);
377c804472Sopenharmony_ci    }
387c804472Sopenharmony_ci
397c804472Sopenharmony_ci    InitPipe(pipeName, pipePort);
407c804472Sopenharmony_ci    if ((!CommandParser::GetInstance().IsResolutionValid(orignalResolutionWidth)) ||
417c804472Sopenharmony_ci        (!CommandParser::GetInstance().IsResolutionValid(orignalResolutionHeight))) {
427c804472Sopenharmony_ci        ELOG("VirtualScreen::InitAll invalid resolution, width : %d height : %d", orignalResolutionWidth,
437c804472Sopenharmony_ci             orignalResolutionHeight);
447c804472Sopenharmony_ci        return;
457c804472Sopenharmony_ci    }
467c804472Sopenharmony_ci
477c804472Sopenharmony_ci    bufferSize = orignalResolutionWidth * orignalResolutionHeight * pixelSize + headSize;
487c804472Sopenharmony_ci    wholeBuffer = new(std::nothrow) uint8_t[LWS_PRE + bufferSize];
497c804472Sopenharmony_ci    if (!wholeBuffer) {
507c804472Sopenharmony_ci        ELOG("Memory allocation failed : wholeBuffer.");
517c804472Sopenharmony_ci        return;
527c804472Sopenharmony_ci    }
537c804472Sopenharmony_ci    regionWholeBuffer = new(std::nothrow) uint8_t[LWS_PRE + bufferSize];
547c804472Sopenharmony_ci    if (!regionWholeBuffer) {
557c804472Sopenharmony_ci        ELOG("Memory allocation failed: regionWholeBuffer.");
567c804472Sopenharmony_ci        return;
577c804472Sopenharmony_ci    }
587c804472Sopenharmony_ci    screenBuffer = wholeBuffer + LWS_PRE;
597c804472Sopenharmony_ci    regionBuffer = regionWholeBuffer + LWS_PRE;
607c804472Sopenharmony_ci    osBuffer = new(std::nothrow) uint8_t[bufferSize];
617c804472Sopenharmony_ci    if (!osBuffer) {
627c804472Sopenharmony_ci        ELOG("Memory allocation failed: osBuffer.");
637c804472Sopenharmony_ci        return;
647c804472Sopenharmony_ci    }
657c804472Sopenharmony_ci    if (screenBuffer == nullptr) {
667c804472Sopenharmony_ci        ELOG("VirtualScreen::InitAll wholeBuffer memory allocation failed");
677c804472Sopenharmony_ci        return;
687c804472Sopenharmony_ci    }
697c804472Sopenharmony_ci    InitBuffer();
707c804472Sopenharmony_ci}
717c804472Sopenharmony_ci
727c804472Sopenharmony_cibool VirtualScreenImpl::IsRectValid(int32_t x1, int32_t y1, int32_t x2, int32_t y2) const
737c804472Sopenharmony_ci{
747c804472Sopenharmony_ci    if (x1 < 0 || y1 < 0) {
757c804472Sopenharmony_ci        return false;
767c804472Sopenharmony_ci    }
777c804472Sopenharmony_ci
787c804472Sopenharmony_ci    if (x2 >= orignalResolutionWidth || y2 >= orignalResolutionHeight) {
797c804472Sopenharmony_ci        return false;
807c804472Sopenharmony_ci    }
817c804472Sopenharmony_ci    return true;
827c804472Sopenharmony_ci}
837c804472Sopenharmony_ci
847c804472Sopenharmony_civoid VirtualScreenImpl::WriteRefreshRegion()
857c804472Sopenharmony_ci{
867c804472Sopenharmony_ci    currentPos = VERSION_POS;
877c804472Sopenharmony_ci    WriteBuffer(protocolVersion);
887c804472Sopenharmony_ci    WriteBuffer(regionX1);
897c804472Sopenharmony_ci    WriteBuffer(regionY1);
907c804472Sopenharmony_ci    regionWidth = static_cast<uint16_t>(orignalResolutionWidth);
917c804472Sopenharmony_ci    WriteBuffer(regionWidth);
927c804472Sopenharmony_ci    regionHeight = static_cast<uint16_t>(orignalResolutionHeight);
937c804472Sopenharmony_ci    WriteBuffer(regionHeight);
947c804472Sopenharmony_ci}
957c804472Sopenharmony_ci
967c804472Sopenharmony_civoid VirtualScreenImpl::UpdateRegion(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
977c804472Sopenharmony_ci{
987c804472Sopenharmony_ci    regionX1 = x1;
997c804472Sopenharmony_ci    regionY1 = y1;
1007c804472Sopenharmony_ci    regionX2 = (x2 < compressionResolutionWidth - extendPix)
1017c804472Sopenharmony_ci                   ? (x2 + extendPix) : (compressionResolutionWidth - 1);
1027c804472Sopenharmony_ci    regionY2 = (y2 < compressionResolutionHeight - extendPix)
1037c804472Sopenharmony_ci                   ? (y2 + extendPix) : (compressionResolutionHeight - 1);
1047c804472Sopenharmony_ci    regionWidth = regionX2 - regionX1 + 1;
1057c804472Sopenharmony_ci    regionHeight = regionY2 - regionY1 + 1;
1067c804472Sopenharmony_ci}
1077c804472Sopenharmony_ci
1087c804472Sopenharmony_civoid VirtualScreenImpl::InitBuffer()
1097c804472Sopenharmony_ci{
1107c804472Sopenharmony_ci    currentPos = 0;
1117c804472Sopenharmony_ci    WriteBuffer(headStart);
1127c804472Sopenharmony_ci    WriteBuffer(orignalResolutionWidth);
1137c804472Sopenharmony_ci    WriteBuffer(orignalResolutionHeight);
1147c804472Sopenharmony_ci    WriteBuffer(compressionResolutionWidth);
1157c804472Sopenharmony_ci    WriteBuffer(compressionResolutionHeight);
1167c804472Sopenharmony_ci}
1177c804472Sopenharmony_ci
1187c804472Sopenharmony_civoid VirtualScreenImpl::ScheduleBufferSend()
1197c804472Sopenharmony_ci{
1207c804472Sopenharmony_ci    if (!isChanged) {
1217c804472Sopenharmony_ci        return;
1227c804472Sopenharmony_ci    }
1237c804472Sopenharmony_ci
1247c804472Sopenharmony_ci    if (!isWebSocketConfiged) {
1257c804472Sopenharmony_ci        ELOG("image socket is not ready");
1267c804472Sopenharmony_ci        return;
1277c804472Sopenharmony_ci    }
1287c804472Sopenharmony_ci    isFrameUpdated = true;
1297c804472Sopenharmony_ci    if (CommandParser::GetInstance().IsRegionRefresh()) {
1307c804472Sopenharmony_ci        SendFullBuffer();
1317c804472Sopenharmony_ci    } else {
1327c804472Sopenharmony_ci        SendFullBuffer();
1337c804472Sopenharmony_ci    }
1347c804472Sopenharmony_ci    if (isFirstSend) {
1357c804472Sopenharmony_ci        ILOG("Send first buffer finish");
1367c804472Sopenharmony_ci        TraceTool::GetInstance().HandleTrace("Send first buffer finish");
1377c804472Sopenharmony_ci        isFirstSend = false;
1387c804472Sopenharmony_ci    }
1397c804472Sopenharmony_ci
1407c804472Sopenharmony_ci    {
1417c804472Sopenharmony_ci        std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
1427c804472Sopenharmony_ci        if (!WebSocketServer::GetInstance().firstImageBuffer) {
1437c804472Sopenharmony_ci            WebSocketServer::GetInstance().firstImageBuffer = new(std::nothrow) uint8_t[LWS_PRE + bufferSize];
1447c804472Sopenharmony_ci            if (!WebSocketServer::GetInstance().firstImageBuffer) {
1457c804472Sopenharmony_ci                ELOG("Memory allocation failed: firstImageBuffer.");
1467c804472Sopenharmony_ci                return;
1477c804472Sopenharmony_ci            }
1487c804472Sopenharmony_ci            WebSocketServer::GetInstance().firstImagebufferSize = headSize + jpgBufferSize;
1497c804472Sopenharmony_ci        }
1507c804472Sopenharmony_ci        std::copy(regionBuffer,
1517c804472Sopenharmony_ci                  regionBuffer + headSize + jpgBufferSize,
1527c804472Sopenharmony_ci                  WebSocketServer::GetInstance().firstImageBuffer + LWS_PRE);
1537c804472Sopenharmony_ci    }
1547c804472Sopenharmony_ci
1557c804472Sopenharmony_ci    sendFrameCountPerMinute++;
1567c804472Sopenharmony_ci    isChanged = false;
1577c804472Sopenharmony_ci}
1587c804472Sopenharmony_ci
1597c804472Sopenharmony_civoid VirtualScreenImpl::Send(unsigned char* data, int32_t width, int32_t height)
1607c804472Sopenharmony_ci{
1617c804472Sopenharmony_ci    if (CommandParser::GetInstance().GetScreenMode() == CommandParser::ScreenMode::STATIC
1627c804472Sopenharmony_ci        && VirtualScreen::isOutOfSeconds) {
1637c804472Sopenharmony_ci        return;
1647c804472Sopenharmony_ci    }
1657c804472Sopenharmony_ci    // if websocket is config, use websocet, else use localsocket
1667c804472Sopenharmony_ci    VirtualScreen::RgbToJpg(data + headSize, width, height);
1677c804472Sopenharmony_ci    std::copy(jpgScreenBuffer, jpgScreenBuffer + jpgBufferSize, regionBuffer + headSize);
1687c804472Sopenharmony_ci    WebSocketServer::GetInstance().WriteData(regionBuffer, headSize + jpgBufferSize);
1697c804472Sopenharmony_ci    FreeJpgMemory();
1707c804472Sopenharmony_ci}
1717c804472Sopenharmony_ci
1727c804472Sopenharmony_civoid VirtualScreenImpl::SendFullBuffer()
1737c804472Sopenharmony_ci{
1747c804472Sopenharmony_ci    WriteRefreshRegion();
1757c804472Sopenharmony_ci    std::copy(screenBuffer, screenBuffer + headSize, regionBuffer);
1767c804472Sopenharmony_ci    Send(reinterpret_cast<unsigned char*>(screenBuffer),
1777c804472Sopenharmony_ci         compressionResolutionWidth,
1787c804472Sopenharmony_ci         compressionResolutionHeight);
1797c804472Sopenharmony_ci}
1807c804472Sopenharmony_ci
1817c804472Sopenharmony_civoid VirtualScreenImpl::SendRegionBuffer()
1827c804472Sopenharmony_ci{
1837c804472Sopenharmony_ci    WriteRefreshRegion();
1847c804472Sopenharmony_ci    std::copy(screenBuffer, screenBuffer + headSize, regionBuffer);
1857c804472Sopenharmony_ci    for (int i = regionY1; i <= regionY2; ++i) {
1867c804472Sopenharmony_ci        uint8_t* startPos = screenBuffer + (i * compressionResolutionWidth + regionX1) * jpgPix + headSize;
1877c804472Sopenharmony_ci        std::copy(startPos,
1887c804472Sopenharmony_ci                  startPos + regionWidth * jpgPix,
1897c804472Sopenharmony_ci                  regionBuffer + ((i - regionY1) * regionWidth) * jpgPix + headSize);
1907c804472Sopenharmony_ci    }
1917c804472Sopenharmony_ci    Send(reinterpret_cast<unsigned char*>(regionBuffer), regionWidth, regionHeight);
1927c804472Sopenharmony_ci}
1937c804472Sopenharmony_ci
1947c804472Sopenharmony_civoid VirtualScreenImpl::FreeJpgMemory()
1957c804472Sopenharmony_ci{
1967c804472Sopenharmony_ci    if (jpgScreenBuffer != nullptr) {
1977c804472Sopenharmony_ci        free(jpgScreenBuffer);
1987c804472Sopenharmony_ci        jpgScreenBuffer = NULL;
1997c804472Sopenharmony_ci    }
2007c804472Sopenharmony_ci}
2017c804472Sopenharmony_ci
2027c804472Sopenharmony_ciVirtualScreenImpl& VirtualScreenImpl::GetInstance()
2037c804472Sopenharmony_ci{
2047c804472Sopenharmony_ci    static VirtualScreenImpl virtualScreen;
2057c804472Sopenharmony_ci    BaseGfxEngine::InitGfxEngine(&virtualScreen);
2067c804472Sopenharmony_ci    return virtualScreen;
2077c804472Sopenharmony_ci}
2087c804472Sopenharmony_ci
2097c804472Sopenharmony_civoid VirtualScreenImpl::CheckBufferSend()
2107c804472Sopenharmony_ci{
2117c804472Sopenharmony_ci    VirtualScreenImpl::GetInstance().ScheduleBufferSend();
2127c804472Sopenharmony_ci}
2137c804472Sopenharmony_ci
2147c804472Sopenharmony_ciVirtualScreenImpl::VirtualScreenImpl()
2157c804472Sopenharmony_ci    : wholeBuffer(nullptr),
2167c804472Sopenharmony_ci      regionWholeBuffer(nullptr),
2177c804472Sopenharmony_ci      screenBuffer(nullptr),
2187c804472Sopenharmony_ci      regionBuffer(nullptr),
2197c804472Sopenharmony_ci      osBuffer(nullptr),
2207c804472Sopenharmony_ci      isChanged(false),
2217c804472Sopenharmony_ci      currentPos(0),
2227c804472Sopenharmony_ci      bufferSize(0),
2237c804472Sopenharmony_ci      isFirstRender(true),
2247c804472Sopenharmony_ci      isFirstSend(true),
2257c804472Sopenharmony_ci      regionX1(0),
2267c804472Sopenharmony_ci      regionY1(0),
2277c804472Sopenharmony_ci      regionX2(0),
2287c804472Sopenharmony_ci      regionY2(0),
2297c804472Sopenharmony_ci      regionWidth(0),
2307c804472Sopenharmony_ci      regionHeight(0),
2317c804472Sopenharmony_ci      bufferInfo(nullptr)
2327c804472Sopenharmony_ci{
2337c804472Sopenharmony_ci}
2347c804472Sopenharmony_ci
2357c804472Sopenharmony_ciVirtualScreenImpl::~VirtualScreenImpl()
2367c804472Sopenharmony_ci{
2377c804472Sopenharmony_ci    if (wholeBuffer != nullptr) {
2387c804472Sopenharmony_ci        delete [] wholeBuffer;
2397c804472Sopenharmony_ci        wholeBuffer = nullptr;
2407c804472Sopenharmony_ci        screenBuffer = nullptr;
2417c804472Sopenharmony_ci    }
2427c804472Sopenharmony_ci    FreeJpgMemory();
2437c804472Sopenharmony_ci    if (WebSocketServer::GetInstance().firstImageBuffer) {
2447c804472Sopenharmony_ci        delete [] WebSocketServer::GetInstance().firstImageBuffer;
2457c804472Sopenharmony_ci        WebSocketServer::GetInstance().firstImageBuffer = nullptr;
2467c804472Sopenharmony_ci    }
2477c804472Sopenharmony_ci}
2487c804472Sopenharmony_ci
2497c804472Sopenharmony_civoid VirtualScreenImpl::Flush(const OHOS::Rect& flushRect)
2507c804472Sopenharmony_ci{
2517c804472Sopenharmony_ci    if (isFirstRender) {
2527c804472Sopenharmony_ci        ILOG("Get first render buffer");
2537c804472Sopenharmony_ci        TraceTool::GetInstance().HandleTrace("Get first render buffer");
2547c804472Sopenharmony_ci        isFirstRender = false;
2557c804472Sopenharmony_ci    }
2567c804472Sopenharmony_ci
2577c804472Sopenharmony_ci    bool staticRet = VirtualScreen::JudgeStaticImage(SEND_IMG_DURATION_MS);
2587c804472Sopenharmony_ci    if (!staticRet) {
2597c804472Sopenharmony_ci        return;
2607c804472Sopenharmony_ci    }
2617c804472Sopenharmony_ci
2627c804472Sopenharmony_ci    for (int i = 0; i <= compressionResolutionHeight - 1; ++i) {
2637c804472Sopenharmony_ci        for (int j = 0; j <= compressionResolutionWidth - 1; ++j) {
2647c804472Sopenharmony_ci            uint8_t* curPixel = screenBuffer + (i * compressionResolutionWidth + j) * jpgPix + headSize;
2657c804472Sopenharmony_ci            uint8_t* osPixel = osBuffer + (i * compressionResolutionWidth + j) * pixelSize + headSize;
2667c804472Sopenharmony_ci            *(curPixel + redPos) = *(osPixel + bluePos);
2677c804472Sopenharmony_ci            *(curPixel + greenPos) = *(osPixel + greenPos);
2687c804472Sopenharmony_ci            *(curPixel + bluePos) = *(osPixel + redPos);
2697c804472Sopenharmony_ci        }
2707c804472Sopenharmony_ci    }
2717c804472Sopenharmony_ci
2727c804472Sopenharmony_ci    validFrameCountPerMinute++;
2737c804472Sopenharmony_ci    isChanged = true;
2747c804472Sopenharmony_ci    ScheduleBufferSend();
2757c804472Sopenharmony_ci}
2767c804472Sopenharmony_ci
2777c804472Sopenharmony_ciOHOS::BufferInfo* VirtualScreenImpl::GetFBBufferInfo()
2787c804472Sopenharmony_ci{
2797c804472Sopenharmony_ci    if (bufferInfo == nullptr) {
2807c804472Sopenharmony_ci        bufferInfo = new(std::nothrow) OHOS::BufferInfo;
2817c804472Sopenharmony_ci        if (!bufferInfo) {
2827c804472Sopenharmony_ci            ELOG("Memory allocation failed: osBuffer.");
2837c804472Sopenharmony_ci            return bufferInfo;
2847c804472Sopenharmony_ci        }
2857c804472Sopenharmony_ci        bufferInfo->rect = {0, 0, compressionResolutionWidth - 1, compressionResolutionHeight - 1};
2867c804472Sopenharmony_ci        bufferInfo->mode = OHOS::ARGB8888;
2877c804472Sopenharmony_ci
2887c804472Sopenharmony_ci        bufferInfo->color = 0x44;
2897c804472Sopenharmony_ci        bufferInfo->phyAddr = bufferInfo->virAddr = osBuffer + headSize;
2907c804472Sopenharmony_ci        // 3: Shift right 3 bits
2917c804472Sopenharmony_ci        bufferInfo->stride = orignalResolutionWidth * (OHOS::DrawUtils::GetPxSizeByColorMode(bufferInfo->mode) >> 3);
2927c804472Sopenharmony_ci        bufferInfo->width = orignalResolutionWidth;
2937c804472Sopenharmony_ci        bufferInfo->height = orignalResolutionHeight;
2947c804472Sopenharmony_ci    }
2957c804472Sopenharmony_ci
2967c804472Sopenharmony_ci    return bufferInfo;
2977c804472Sopenharmony_ci}
2987c804472Sopenharmony_ci
2997c804472Sopenharmony_ciuint16_t VirtualScreenImpl::GetScreenWidth()
3007c804472Sopenharmony_ci{
3017c804472Sopenharmony_ci    return orignalResolutionWidth;
3027c804472Sopenharmony_ci}
3037c804472Sopenharmony_ci
3047c804472Sopenharmony_ciuint16_t VirtualScreenImpl::GetScreenHeight()
3057c804472Sopenharmony_ci{
3067c804472Sopenharmony_ci    return orignalResolutionHeight;
3077c804472Sopenharmony_ci}
308