1 /*
2  * Copyright (c) 2022-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 
16 #include "2.0/include/screenregion.h"
17 
18 #include <securec.h>
19 #include "display_manager.h"
20 #include "dscreen_constants.h"
21 #include "dscreen_errcode.h"
22 #include "dscreen_fwkkit.h"
23 #include "dscreen_hisysevent.h"
24 #include "dscreen_log.h"
25 #include "dscreen_hidumper.h"
26 #include "dscreen_json_util.h"
27 #include "dscreen_util.h"
28 #include "screen.h"
29 #include "screen_client.h"
30 #include "screen_client_common.h"
31 #include "2.0/include/screenregionmgr.h"
32 #include "hitrace_meter.h"
33 #include "dscreen_hitrace.h"
34 
35 namespace OHOS {
36 namespace DistributedHardware {
37 namespace V2_0 {
ScreenRegion(const std::string & remoteDevId)38 ScreenRegion::ScreenRegion(const std::string &remoteDevId) : screenId_(0), displayId_(0), remoteDevId_(remoteDevId)
39 {
40     DHLOGI("ScreenRegion ctor.");
41     frameNumber_.store(0);
42 }
43 
~ScreenRegion()44 ScreenRegion::~ScreenRegion()
45 {
46     DHLOGI("ScreenRegion dctor.");
47     if (receiverAdapter_ != nullptr) {
48         receiverAdapter_->Release();
49     }
50     receiverAdapter_ = nullptr;
51     frameNumber_.store(0);
52 }
53 
InitReceiverEngine(IAVEngineProvider * providerPtr)54 int32_t ScreenRegion::InitReceiverEngine(IAVEngineProvider *providerPtr)
55 {
56     DHLOGI("InitReceiverEngine enter.");
57     if (receiverAdapter_ == nullptr) {
58         receiverAdapter_ = std::make_shared<AVTransReceiverAdapter>();
59     }
60     int32_t ret = receiverAdapter_->Initialize(providerPtr, remoteDevId_);
61     if (ret != DH_SUCCESS) {
62         DHLOGE("initialize av receiver adapter failed.");
63         return ERR_DH_AV_TRANS_INIT_FAILED;
64     }
65     return receiverAdapter_->RegisterAdapterCallback(shared_from_this());
66 }
67 
Release()68 int32_t ScreenRegion::Release()
69 {
70     DHLOGI("ScreenRegion::Release remoteDevId: %{public}s", GetAnonyString(remoteDevId_).c_str());
71     if (!isRunning) {
72         DHLOGI("ScreenRegion not running, no need release");
73         return DH_SUCCESS;
74     }
75     ScreenClient::GetInstance().RemoveWindow(windowId_);
76 
77     if (receiverAdapter_ == nullptr) {
78         DHLOGE("av transport receiver adapter is nullptr.");
79         return ERR_DH_AV_TRANS_NULL_VALUE;
80     }
81 
82     int32_t ret = receiverAdapter_->Stop();
83     if (ret != DH_SUCCESS) {
84         DHLOGE("sink trans stop failed.");
85     }
86 
87     ret = receiverAdapter_->Release();
88     if (ret != DH_SUCCESS) {
89         DHLOGE("release av receiver adapter failed.");
90     }
91 
92     isRunning = false;
93     return DH_SUCCESS;
94 }
95 
StartReceiverEngine(const std::string & content)96 int32_t ScreenRegion::StartReceiverEngine(const std::string &content)
97 {
98     DHLOGI("StartReceiverEngine enter.");
99     if (receiverAdapter_ == nullptr) {
100         DHLOGE("av transport receiver adapter is null.");
101         return ERR_DH_AV_TRANS_NULL_VALUE;
102     }
103     int32_t ret = SetUp(content);
104     if (ret != DH_SUCCESS) {
105         DHLOGE("set up av receiver parameter failed.");
106         return ERR_DH_AV_TRANS_SETUP_FAILED;
107     }
108     ret = receiverAdapter_->Start();
109     if (ret != DH_SUCCESS) {
110         DHLOGE("start av receiver engine failed, remove window.");
111         (void)ScreenClient::GetInstance().RemoveWindow(windowId_);
112         return ERR_DH_AV_TRANS_START_FAILED;
113     }
114     isRunning = true;
115     PublishMessage(DHTopic::TOPIC_SINK_PROJECT_WINDOW_INFO, screenId_, remoteDevId_, windowId_, windowProperty_);
116     return DH_SUCCESS;
117 }
118 
StopReceiverEngine()119 int32_t ScreenRegion::StopReceiverEngine()
120 {
121     DHLOGI("StopReceiverEngine, remoteDevId: %{public}s, screenId is: %{public}" PRIu64,
122         GetAnonyString(remoteDevId_).c_str(), screenId_);
123     int32_t ret = ScreenClient::GetInstance().RemoveWindow(windowId_);
124     if (ret != DH_SUCCESS) {
125         DHLOGE("remove window failed.");
126     }
127     if (receiverAdapter_ == nullptr) {
128         DHLOGE("av transport receiver adapter is null.");
129         return ERR_DH_AV_TRANS_NULL_VALUE;
130     }
131     return receiverAdapter_->Stop();
132 }
133 
SetUp(const std::string & content)134 int32_t ScreenRegion::SetUp(const std::string &content)
135 {
136     json contentJson = json::parse(content, nullptr, false);
137     if (contentJson.is_discarded()) {
138         return ERR_DH_SCREEN_INPUT_PARAM_INVALID;
139     }
140     if (!CheckContentJson(contentJson) || !contentJson.contains(KEY_VIDEO_PARAM) ||
141         !contentJson.contains(KEY_MAPRELATION)) {
142         return ERR_DH_SCREEN_INPUT_PARAM_INVALID;
143     }
144     screenId_ = contentJson[KEY_SCREEN_ID].get<uint64_t>();
145     displayId_ = Rosen::DisplayManager::GetInstance().GetDefaultDisplayId();
146     videoParam_ = std::make_shared<VideoParam>(contentJson[KEY_VIDEO_PARAM].get<VideoParam>());
147     mapRelation_ = std::make_shared<DScreenMapRelation>(contentJson[KEY_MAPRELATION].get<DScreenMapRelation>());
148 
149     int32_t ret = ConfigWindow();
150     if (ret != DH_SUCCESS) {
151         DHLOGE("config dscreen region window failed.");
152         return ret;
153     }
154 
155     ret = SetReceiverAdapterParameters();
156     if (ret != DH_SUCCESS) {
157         DHLOGE("Failed to set receiver adapter parameters, error code: %{public}d", ret);
158         return ret;
159     }
160 
161     ret = SetAlignedHeight();
162     if (ret != DH_SUCCESS) {
163         DHLOGE("Failed to set aligned height, error code: %{public}d", ret);
164         return ret;
165     }
166 
167     return DH_SUCCESS;
168 }
169 
ConfigWindow()170 int32_t ScreenRegion::ConfigWindow()
171 {
172     DHLOGI("ConfigWindow enter");
173     if (mapRelation_ == nullptr) {
174         DHLOGE("mapRelation is nullptr.");
175         return ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED;
176     }
177     ScreenRect screenRect = mapRelation_->GetScreenRect();
178     std::shared_ptr<WindowProperty> windowProperty = std::make_shared<WindowProperty>(WindowProperty {
179         .displayId = displayId_,
180         .startX = screenRect.startX,
181         .startY = screenRect.startY,
182         .width = screenRect.width,
183         .height = screenRect.height
184     });
185     windowProperty_ = windowProperty;
186     windowId_ = ScreenClient::GetInstance().AddWindow(windowProperty);
187     if (windowId_ < 0) {
188         DHLOGE("Add window failed.");
189         ReportOptFail(DSCREEN_OPT_FAIL, ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED, "Add window failed.");
190         return ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED;
191     }
192     int32_t ret = ScreenClient::GetInstance().ShowWindow(windowId_);
193     if (ret != DH_SUCCESS) {
194         DHLOGE("Show window failed.");
195         ReportOptFail(DSCREEN_OPT_FAIL, ret, "Show window failed.");
196         return ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED;
197     }
198 
199     sptr<Surface> surface = ScreenClient::GetInstance().GetSurface(windowId_);
200     if (surface == nullptr) {
201         DHLOGE("Get window surface failed.");
202         ReportOptFail(DSCREEN_OPT_FAIL, ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED, "Get window surface failed.");
203         return ERR_DH_SCREEN_SA_DSCREEN_SCREENGION_SETUP_FAILED;
204     }
205     windowSurface_ = surface;
206     return DH_SUCCESS;
207 }
208 
SetReceiverAdapterParameters()209 int32_t ScreenRegion::SetReceiverAdapterParameters()
210 {
211     if (videoParam_ == nullptr) {
212         DHLOGE("videoParam is nullptr.");
213         return ERR_DH_AV_TRANS_NULL_VALUE;
214     }
215 
216     if (receiverAdapter_ == nullptr) {
217         DHLOGE("receiverAdapter is nullptr.");
218         return ERR_DH_AV_TRANS_NULL_VALUE;
219     }
220 
221     std::string codecType;
222     if (videoParam_->GetCodecType() == VIDEO_CODEC_TYPE_VIDEO_H265) {
223         codecType = MIME_VIDEO_H265;
224     } else if (videoParam_->GetCodecType() == VIDEO_CODEC_TYPE_VIDEO_H264) {
225         codecType = MIME_VIDEO_H264;
226     } else {
227         codecType = MIME_VIDEO_RAW;
228     }
229     std::string pixelFormat;
230     if (videoParam_->GetVideoFormat() == VIDEO_DATA_FORMAT_YUVI420) {
231         pixelFormat = VIDEO_FORMAT_YUVI420;
232     } else if (videoParam_->GetVideoFormat() == VIDEO_DATA_FORMAT_NV12) {
233         pixelFormat = VIDEO_FORMAT_NV12;
234     } else if (videoParam_->GetVideoFormat() == VIDEO_DATA_FORMAT_NV21) {
235         pixelFormat = VIDEO_FORMAT_NV21;
236     } else {
237         pixelFormat = VIDEO_FORMAT_RGBA8888;
238     }
239     receiverAdapter_->SetParameter(AVTransTag::VIDEO_CODEC_TYPE, codecType);
240     receiverAdapter_->SetParameter(AVTransTag::VIDEO_PIXEL_FORMAT, pixelFormat);
241     receiverAdapter_->SetParameter(AVTransTag::VIDEO_WIDTH, std::to_string(videoParam_->GetVideoWidth()));
242     receiverAdapter_->SetParameter(AVTransTag::VIDEO_HEIGHT, std::to_string(videoParam_->GetVideoHeight()));
243     receiverAdapter_->SetParameter(AVTransTag::VIDEO_FRAME_RATE, std::to_string(videoParam_->GetFps()));
244     receiverAdapter_->SetParameter(AVTransTag::ENGINE_READY, OWNER_NAME_D_SCREEN);
245 
246     return DH_SUCCESS;
247 }
248 
SetAlignedHeight()249 int32_t ScreenRegion::SetAlignedHeight()
250 {
251     if (videoParam_ == nullptr) {
252         DHLOGE("video parameter is nullptr.");
253         return ERR_DH_AV_TRANS_NULL_VALUE;
254     }
255 
256     alignedHeight_ = videoParam_->GetVideoHeight();
257     if (alignedHeight_ % ALIGNEDBITS != 0) {
258         alignedHeight_ = ((alignedHeight_ / ALIGNEDBITS) + 1) * ALIGNEDBITS;
259     }
260 
261     return DH_SUCCESS;
262 }
263 
PublishMessage(const DHTopic topic,const uint64_t & screenId,const std::string & remoteDevId,const int32_t & windowId,std::shared_ptr<WindowProperty> windowProperty)264 void ScreenRegion::PublishMessage(const DHTopic topic, const uint64_t &screenId,
265     const std::string &remoteDevId, const int32_t &windowId, std::shared_ptr<WindowProperty> windowProperty)
266 {
267     DHLOGI("ScreenRegion PublishMessage");
268     if (DScreenFwkKit::GetInstance().GetDHFwkKit() == nullptr) {
269         DHLOGE("GetDHFwkKit fail.");
270         return;
271     }
272 
273     if (windowProperty == nullptr) {
274         DHLOGE("windowProperty is nullptr.");
275         return;
276     }
277 
278     json messageJosn;
279     std::string message;
280     messageJosn[SOURCE_WIN_ID] = screenId;
281     messageJosn[SINK_SHOW_WIN_ID] = windowId;
282     messageJosn[SOURCE_DEV_ID] = remoteDevId;
283     messageJosn[SINK_PROJ_SHOW_WIDTH] = windowProperty->width;
284     messageJosn[SINK_PROJ_SHOW_HEIGHT] = windowProperty->height;
285     messageJosn[SINK_WIN_SHOW_X] = windowProperty->startX;
286     messageJosn[SINK_WIN_SHOW_Y] = windowProperty->startY;
287     message = messageJosn.dump();
288     DScreenFwkKit::GetInstance().GetDHFwkKit()->PublishMessage(topic, message);
289 }
290 
OnEngineEvent(DScreenEventType event,const std::string & content)291 void ScreenRegion::OnEngineEvent(DScreenEventType event, const std::string &content)
292 {
293     if (event == DScreenEventType::ENGINE_ERROR) {
294         StopReceiverEngine();
295     } else if (event == DScreenEventType::TRANS_CHANNEL_CLOSED) {
296         ScreenRegionManager::GetInstance().DestoryDScreenRegion(content);
297     }
298 }
299 
OnEngineMessage(const std::shared_ptr<AVTransMessage> & message)300 void ScreenRegion::OnEngineMessage(const std::shared_ptr<AVTransMessage> &message)
301 {
302     if (message == nullptr) {
303         DHLOGE("received engine message is null.");
304         return;
305     }
306 
307     DHLOGI("On source device engine message received, message type =%{public}d.", message->type_);
308     if (message->type_ == DScreenMsgType::START_MIRROR) {
309         int32_t ret = StartReceiverEngine(message->content_);
310         DScreenMsgType msgType = (ret == DH_SUCCESS) ? DScreenMsgType::START_MIRROR_SUCCESS :
311             DScreenMsgType::START_MIRROR_FAIL;
312 
313         json paramJson;
314         paramJson[KEY_DEV_ID] = remoteDevId_;
315         auto avMessage = std::make_shared<AVTransMessage>(msgType, paramJson.dump(), remoteDevId_);
316 
317         if (receiverAdapter_ == nullptr) {
318             DHLOGE("av transport receiver adapter is nullptr.");
319             return;
320         }
321 
322         receiverAdapter_->SendMessageToRemote(avMessage);
323     } else if (message->type_ == DScreenMsgType::STOP_MIRROR) {
324         StopReceiverEngine();
325     }
326 }
327 
GetWSBuffer(sptr<OHOS::SurfaceBuffer> & wsBuffer,const std::shared_ptr<AVTransBuffer> & buffer)328 void ScreenRegion::GetWSBuffer(sptr<OHOS::SurfaceBuffer> &wsBuffer, const std::shared_ptr<AVTransBuffer> &buffer)
329 {
330     if ((wsBuffer == nullptr) || (buffer == nullptr)) {
331         DHLOGE("wsBuffer or buffer is nullptr.");
332         return;
333     }
334 
335     if ((videoParam_ == nullptr) || (windowSurface_ == nullptr)) {
336         DHLOGE("videoParam or windowSurface is nullptr.");
337         return;
338     }
339 
340     auto bufferData = buffer->GetBufferData(0);
341     if (bufferData == nullptr) {
342         DHLOGE("bufferData is null.");
343         return;
344     }
345     auto bufferAddr = bufferData->GetAddress();
346     auto wsBufAddr = static_cast<uint8_t*>(wsBuffer->GetVirAddr());
347     uint32_t wsBufSize = wsBuffer->GetSize();
348     uint32_t srcOffset = 0;
349     uint32_t dstOffset = 0;
350     uint32_t alignedWidth = videoParam_->GetVideoWidth();
351     uint32_t chromaOffset = videoParam_->GetVideoWidth() * videoParam_->GetVideoHeight();
352 
353     for (unsigned int yh = 0 ; yh < videoParam_->GetVideoHeight(); yh++) {
354         int32_t ret = memcpy_s(wsBufAddr + dstOffset, chromaOffset - dstOffset,
355             bufferAddr + srcOffset, videoParam_->GetVideoWidth());
356         if (ret != EOK) {
357             DHLOGE("memcpy video buffer y data failed,ret: %{public}d.", ret);
358             windowSurface_->CancelBuffer(wsBuffer);
359             return;
360         }
361         dstOffset += videoParam_->GetVideoWidth();
362         srcOffset += alignedWidth;
363     }
364 
365     dstOffset = chromaOffset;
366     srcOffset = alignedWidth * alignedHeight_;
367 
368     for (unsigned int uvh = 0 ; uvh < videoParam_->GetVideoHeight() / TWO; uvh++) {
369         int32_t ret = memcpy_s(wsBufAddr + dstOffset, wsBufSize - dstOffset,
370             bufferAddr + srcOffset, videoParam_->GetVideoWidth());
371         if (ret != EOK) {
372             DHLOGE("memcpy video buffer uv data failed,ret: %{public}d.", ret);
373             windowSurface_->CancelBuffer(wsBuffer);
374             return;
375         }
376         dstOffset += videoParam_->GetVideoWidth();
377         srcOffset += alignedWidth;
378     }
379 }
380 
OnEngineDataDone(const std::shared_ptr<AVTransBuffer> & buffer)381 void ScreenRegion::OnEngineDataDone(const std::shared_ptr<AVTransBuffer> &buffer)
382 {
383     ++frameNumber_;
384     DHLOGI("OnEngineDataDone enter");
385     if (buffer == nullptr) {
386         DHLOGE("received video buffer data is nullptr.");
387         return;
388     }
389     if ((windowSurface_ == nullptr) || (videoParam_ == nullptr)) {
390         DHLOGE("windowSurface or videoParam is nullptr.");
391         return;
392     }
393     sptr<OHOS::SurfaceBuffer> wsBuffer = nullptr;
394     int32_t releaseFence = -1;
395     OHOS::BufferRequestConfig requestConfig = {
396         .width = videoParam_->GetVideoWidth(),
397         .height = videoParam_->GetVideoHeight(),
398         .strideAlignment = STRIDE_ALIGNMENT,
399         .format = GRAPHIC_PIXEL_FMT_YCRCB_420_SP,
400         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
401     };
402     SurfaceError surfaceErr = windowSurface_->RequestBuffer(wsBuffer, releaseFence, requestConfig);
403     if (surfaceErr != SURFACE_ERROR_OK || wsBuffer == nullptr) {
404         DHLOGE("surface request buffer failed, surfaceErr: %{public}d.", surfaceErr);
405         windowSurface_->CancelBuffer(wsBuffer);
406         return;
407     }
408     GetWSBuffer(wsBuffer, buffer);
409 #ifdef DUMP_DSCREENREGION_FILE
410     uint32_t surBufSize = wsBuffer->GetSize();
411     auto surBufAddr = static_cast<uint8_t *>(wsBuffer->GetVirAddr());
412     int64_t timestamp = 0;
413     VideoData data = {surBufAddr, surBufSize, requestConfig.width, requestConfig.height, timestamp, "ycbcr_sp420"};
414     if (DscreenHidumper::GetInstance().GetFlagStatus() == true) {
415         DHLOGE("HidumperFlag_ = true, exec SaveFile");
416         DscreenHidumper::GetInstance().SaveFile("Screen_AfterEncoding_width(", data);
417     }
418 #endif
419     BufferFlushConfig flushConfig = { {0, 0, wsBuffer->GetWidth(), wsBuffer->GetHeight()}, 0};
420     StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SINK_PUSH_DATA_TO_WINDOW_START);
421     surfaceErr = windowSurface_->FlushBuffer(wsBuffer, -1, flushConfig);
422     FinishTrace(DSCREEN_HITRACE_LABEL);
423     if (surfaceErr != SURFACE_ERROR_OK) {
424         DHLOGE("surface flush buffer failed, surfaceErr: %{public}d.", surfaceErr);
425         windowSurface_->CancelBuffer(wsBuffer);
426         return;
427     }
428     DHLOGI("Fill video buffer data to window surface success. frameNumber: %{public}" PRIu32, frameNumber_.load());
429 }
430 
GetScreenId()431 uint64_t ScreenRegion::GetScreenId()
432 {
433     return screenId_;
434 }
435 
GetRemoteDevId()436 std::string ScreenRegion::GetRemoteDevId()
437 {
438     return remoteDevId_;
439 }
440 
GetWindowId()441 int32_t ScreenRegion::GetWindowId()
442 {
443     return windowId_;
444 }
445 
GetVideoParam()446 std::shared_ptr<VideoParam> ScreenRegion::GetVideoParam()
447 {
448     return videoParam_;
449 }
450 
GetWindowProperty()451 std::shared_ptr<WindowProperty> ScreenRegion::GetWindowProperty()
452 {
453     return windowProperty_;
454 }
455 
CheckContentJson(json & contentJson)456 bool ScreenRegion::CheckContentJson(json &contentJson)
457 {
458     if (!IsUInt64(contentJson, KEY_SCREEN_ID)) {
459         return false;
460     }
461     return true;
462 }
463 } // namespace V1_0
464 } // namespace DistributedHardware
465 } // namespace OHOS
466