1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 "video_source_screen.h"
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <iostream>
21 #include <unistd.h>
22 #include "common/const_def.h"
23 #include "display_manager.h"
24 #include "display_type.h"
25 #include "media_log.h"
26 #include "screen.h"
27 #include "screen_manager.h"
28 #include "sharing_log.h"
29 #include "sync_fence.h"
30
31 namespace OHOS {
32 namespace Sharing {
33 using namespace std;
34 static constexpr uint32_t MIN_QUEUE_SIZE = 3;
35 static constexpr uint32_t IM_STATUS_SUCCESS = 0;
36 static constexpr uint32_t MILLI_PER_SECOND = 1000;
37
38 static BufferRequestConfig g_requestConfig = {.width = DEFAULT_VIDEO_WIDTH,
39 .height = DEFAULT_VIDEO_HEIGHT,
40 .strideAlignment = 8,
41 .format = PIXEL_FMT_RGBA_8888,
42 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_MEM_DMA,
43 .timeout = 0};
44
45 static BufferFlushConfig g_flushConfig = {
46 .damage =
47 {
48 .x = 0,
49 .y = 0,
50 .w = DEFAULT_VIDEO_WIDTH,
51 .h = DEFAULT_VIDEO_HEIGHT,
52 },
53 .timestamp = 0,
54 };
55
CopySurfaceBuffer(sptr<OHOS::SurfaceBuffer> srcBuffer,sptr<OHOS::SurfaceBuffer> dstBuffer)56 static uint32_t CopySurfaceBuffer(sptr<OHOS::SurfaceBuffer> srcBuffer, sptr<OHOS::SurfaceBuffer> dstBuffer)
57 {
58 SHARING_LOGD("trace.");
59 return IM_STATUS_SUCCESS;
60 }
61
OnChange(const std::vector<uint64_t> & screenIds,Rosen::ScreenGroupChangeEvent event)62 void VideoSourceScreen::ScreenGroupListener::OnChange(const std::vector<uint64_t> &screenIds,
63 Rosen::ScreenGroupChangeEvent event)
64 {
65 SHARING_LOGD("trace.");
66 switch (event) {
67 case Rosen::ScreenGroupChangeEvent::ADD_TO_GROUP:
68 SHARING_LOGD("ADD_TO_GROUP done!");
69 break;
70 case Rosen::ScreenGroupChangeEvent::REMOVE_FROM_GROUP:
71 SHARING_LOGD("REMOVE_FROM_GROUP done!");
72 break;
73 case Rosen::ScreenGroupChangeEvent::CHANGE_GROUP:
74 SHARING_LOGD("CHANGE_GROUP done!");
75 break;
76 default:
77 break;
78 }
79 }
80
OnBufferAvailable()81 void VideoSourceScreen::ScreenBufferConsumerListener::OnBufferAvailable()
82 {
83 SHARING_LOGD("trace.");
84 if (auto parent = parent_.lock()) {
85 parent->OnScreenBufferAvailable();
86 }
87 }
88
~VideoSourceScreen()89 VideoSourceScreen::~VideoSourceScreen()
90 {
91 SHARING_LOGD("trace.");
92
93 std::lock_guard<std::mutex> lk(frameRateCtrlMutex_);
94 if (lastBuffer_) {
95 consumerSurface_->ReleaseBuffer(lastBuffer_, SyncFence::INVALID_FENCE);
96 }
97 lastBuffer_ = nullptr;
98 encoderSurface_ = nullptr;
99 producerSurface_ = nullptr;
100 consumerSurface_ = nullptr;
101 }
102
FrameRateControlTimerWorker()103 void VideoSourceScreen::FrameRateControlTimerWorker()
104 {
105 int32_t fence = -1;
106 sptr<OHOS::SurfaceBuffer> encSurfBuffer = nullptr;
107
108 std::unique_lock<std::mutex> lock(frameRateCtrlMutex_);
109 if (lastBuffer_ == nullptr && lastEncFrameBufferSeq_ == INVALID_SEQ) {
110 return;
111 }
112 lock.unlock();
113
114 GSError ret = encoderSurface_->RequestBuffer(encSurfBuffer, fence, g_requestConfig);
115 if (ret != SURFACE_ERROR_OK) {
116 SHARING_LOGE("RequestBuffer failed, ret:%{public}d!", ret);
117 return;
118 }
119
120 OHOS::sptr<SyncFence> encFence = new SyncFence(fence);
121 encFence->Wait(40); // 40: timeout
122 if (encSurfBuffer == nullptr) {
123 SHARING_LOGE("RequestBuffer failed, encSurfBuffer is null!");
124 return;
125 }
126
127 lock.lock();
128 if (lastBuffer_ != nullptr) {
129 uint32_t result = CopySurfaceBuffer(lastBuffer_, encSurfBuffer);
130 if (result != IM_STATUS_SUCCESS) {
131 SHARING_LOGE("CopySurfaceBuffer failed, error code: %{public}d!", ret);
132 }
133
134 if (consumerSurface_->ReleaseBuffer(lastBuffer_, SyncFence::INVALID_FENCE) != SURFACE_ERROR_OK) {
135 SHARING_LOGE("ReleaseBuffer failed! seq:%{public}u!", lastBuffer_->GetSeqNum());
136 }
137 lastBuffer_ = nullptr;
138 lock.unlock();
139
140 if (encoderSurface_->FlushBuffer(encSurfBuffer, fence, g_flushConfig) == SURFACE_ERROR_OK) {
141 lastEncFrameBufferSeq_ = encSurfBuffer->GetSeqNum();
142 lastEncFrameBuffer_ = encSurfBuffer;
143 } else {
144 SHARING_LOGE("Flush new Surface Buffer failed!");
145 }
146 return;
147 } else {
148 lock.unlock();
149 if (encSurfBuffer->GetSeqNum() != lastEncFrameBufferSeq_) {
150 CopySurfaceBuffer(lastEncFrameBuffer_, encSurfBuffer);
151 }
152 if (encoderSurface_->FlushBuffer(encSurfBuffer, fence, g_flushConfig) != SURFACE_ERROR_OK) {
153 SHARING_LOGE("Flush last Surface Buffer failed!");
154 }
155 return;
156 }
157 }
158
OnScreenBufferAvailable()159 void VideoSourceScreen::OnScreenBufferAvailable()
160 {
161 SHARING_LOGD("trace.");
162 int64_t timestamp = 0;
163 OHOS::Rect damage;
164 OHOS::sptr<OHOS::SurfaceBuffer> buffer = nullptr;
165 OHOS::sptr<SyncFence> screenFence = nullptr;
166 std::unique_lock<std::mutex> lock(frameRateCtrlMutex_);
167 if (consumerSurface_ == nullptr) {
168 SHARING_LOGE("consumer_ is nullptr!");
169 return;
170 }
171 consumerSurface_->AcquireBuffer(buffer, screenFence, timestamp, damage);
172 if (buffer == nullptr || screenFence == nullptr) {
173 SHARING_LOGE("AcquireBuffer failed!");
174 return;
175 }
176
177 screenFence->Wait(40); // 40: sync timeout
178 SHARING_LOGD("AcquireBuffer success! seq:%{public}d, time:%{public}" PRId64 ", fence:%{public}d.",
179 buffer->GetSeqNum(), timestamp, screenFence->Get());
180
181 if (lastBuffer_ != nullptr) {
182 if (consumerSurface_->ReleaseBuffer(lastBuffer_, SyncFence::INVALID_FENCE) != SURFACE_ERROR_OK) {
183 SHARING_LOGE("ReleaseBuffer failed! seq:%{public}u!", lastBuffer_->GetSeqNum());
184 }
185 }
186 lastBuffer_ = buffer;
187 }
188
InitScreenSource(const VideoSourceConfigure & configure)189 int32_t VideoSourceScreen::InitScreenSource(const VideoSourceConfigure &configure)
190 {
191 SHARING_LOGD("trace.");
192 if (encoderSurface_ == nullptr) {
193 SHARING_LOGE("encoderSurface_ is null!");
194 return ERR_GENERAL_ERROR;
195 }
196
197 consumerSurface_ = OHOS::Surface::CreateSurfaceAsConsumer();
198 if (consumerSurface_ == nullptr) {
199 SHARING_LOGE("CreateSurfaceAsConsumer failed!");
200 return ERR_GENERAL_ERROR;
201 }
202
203 queueSzie_ = encoderSurface_->GetQueueSize();
204 if (queueSzie_ < MIN_QUEUE_SIZE) {
205 queueSzie_ = MIN_QUEUE_SIZE;
206 encoderSurface_->SetQueueSize(queueSzie_);
207 }
208 consumerSurface_->SetQueueSize(queueSzie_);
209
210 SHARING_LOGD("consumerSurface_ qid:%{public}" PRIu64 ", encoderSurface_ qid:%{public}" PRIu64 ".",
211 consumerSurface_->GetUniqueId(), encoderSurface_->GetUniqueId());
212
213 auto bufferProducer = consumerSurface_->GetProducer();
214 producerSurface_ = OHOS::Surface::CreateSurfaceAsProducer(bufferProducer);
215
216 screenBufferListener_ = new ScreenBufferConsumerListener(shared_from_this());
217 sptr<IBufferConsumerListener> bufferConsumerListener = move(screenBufferListener_);
218 consumerSurface_->RegisterConsumerListener(bufferConsumerListener);
219
220 timer_->Register(std::bind(&VideoSourceScreen::FrameRateControlTimerWorker, this),
221 MILLI_PER_SECOND / configure.frameRate_);
222 timer_->Setup();
223 SHARING_LOGD("interval::%{public}d.", MILLI_PER_SECOND / configure.frameRate_);
224 RegisterScreenGroupListener();
225 CreateVirtualScreen(configure);
226 srcScreenId_ = configure.srcScreenId_;
227 return ERR_OK;
228 }
229
ReleaseScreenBuffer() const230 int32_t VideoSourceScreen::ReleaseScreenBuffer() const
231 {
232 SHARING_LOGD("trace.");
233 return ERR_OK;
234 }
235
RegisterScreenGroupListener()236 int32_t VideoSourceScreen::RegisterScreenGroupListener()
237 {
238 SHARING_LOGD("trace.");
239 if (screenGroupListener_ == nullptr) {
240 screenGroupListener_ = new ScreenGroupListener();
241 }
242 auto ret = Rosen::ScreenManager::GetInstance().RegisterScreenGroupListener(screenGroupListener_);
243 if (ret != OHOS::Rosen::DMError::DM_OK) {
244 SHARING_LOGE("RegisterScreenGroupListener Failed!");
245 return ERR_GENERAL_ERROR;
246 }
247 SHARING_LOGD("Register successed!");
248 return ERR_OK;
249 }
250
UnregisterScreenGroupListener() const251 int32_t VideoSourceScreen::UnregisterScreenGroupListener() const
252 {
253 SHARING_LOGD("trace.");
254 auto ret = Rosen::ScreenManager::GetInstance().UnregisterScreenGroupListener(screenGroupListener_);
255 if (ret != OHOS::Rosen::DMError::DM_OK) {
256 SHARING_LOGE("UnregisterScreenGroupListener Failed!");
257 return ERR_GENERAL_ERROR;
258 }
259 return ERR_OK;
260 }
261
CreateVirtualScreen(const VideoSourceConfigure & configure)262 uint64_t VideoSourceScreen::CreateVirtualScreen(const VideoSourceConfigure &configure)
263 {
264 SHARING_LOGD("CreateVirtualScreen, width: %{public}u, height: %{public}u.", configure.screenWidth_,
265 configure.screenHeight_);
266 std::string screenName = "MIRACAST_HOME_SCREEN";
267 Rosen::VirtualScreenOption option = {screenName,
268 configure.screenWidth_,
269 configure.screenHeight_,
270 DEFAULT_SCREEN_DENSITY,
271 producerSurface_,
272 DEFAULT_SCREEN_FLAGS,
273 false};
274
275 screenId_ = Rosen::ScreenManager::GetInstance().CreateVirtualScreen(option);
276 SHARING_LOGD("virtualScreen id is: %{public}" PRIu64 ".", screenId_);
277
278 return screenId_;
279 }
280
DestroyVirtualScreen() const281 int32_t VideoSourceScreen::DestroyVirtualScreen() const
282 {
283 SHARING_LOGD("trace.");
284 if (screenId_ == SCREEN_ID_INVALID) {
285 SHARING_LOGE("Failed, invalid screenId!");
286 return ERR_GENERAL_ERROR;
287 }
288 SHARING_LOGD("Destroy virtual screen, screenId: %{public}" PRIu64 ".", screenId_);
289 Rosen::DMError err = Rosen::ScreenManager::GetInstance().DestroyVirtualScreen(screenId_);
290 if (err != Rosen::DMError::DM_OK) {
291 SHARING_LOGE("Destroy virtual screen failed, screenId:%{public}" PRIu64 "!", screenId_);
292 return ERR_GENERAL_ERROR;
293 }
294 return ERR_OK;
295 }
296
StartScreenSourceCapture()297 void VideoSourceScreen::StartScreenSourceCapture()
298 {
299 SHARING_LOGD("trace.");
300 std::vector<uint64_t> mirrorIds;
301 mirrorIds.push_back(screenId_);
302 Rosen::ScreenId groupId = 0;
303 Rosen::DMError err = Rosen::ScreenManager::GetInstance().MakeMirror(srcScreenId_, mirrorIds, groupId);
304 if (err != Rosen::DMError::DM_OK) {
305 SHARING_LOGE("MakeMirror failed, screenId:%{public}" PRIu64 "!", screenId_);
306 }
307 }
308
StopScreenSourceCapture()309 void VideoSourceScreen::StopScreenSourceCapture()
310 {
311 SHARING_LOGD("trace.");
312 UnregisterScreenGroupListener();
313 consumerSurface_->UnregisterConsumerListener();
314 if (timer_ != nullptr) {
315 timer_->Shutdown();
316 timer_.reset();
317 }
318
319 int32_t ret = DestroyVirtualScreen();
320 if (ret != ERR_OK) {
321 SHARING_LOGE("Destroy virtual screen failed!");
322 } else {
323 SHARING_LOGD("Destroy virtual screen success!");
324 }
325 }
326
SetEncoderSurface(sptr<OHOS::Surface> surface)327 int32_t VideoSourceScreen::SetEncoderSurface(sptr<OHOS::Surface> surface)
328 {
329 SHARING_LOGD("trace.");
330 if (screenId_ == SCREEN_ID_INVALID) {
331 SHARING_LOGE("Failed, invalid screenId!");
332 }
333 if (surface == nullptr) {
334 SHARING_LOGE("Surface is nullptr!");
335 return ERR_GENERAL_ERROR;
336 }
337 SHARING_LOGD("Set surface for virtual screen, screenId: %{public}" PRIu64 ".", screenId_);
338 Rosen::DMError err = Rosen::ScreenManager::GetInstance().SetVirtualScreenSurface(screenId_, surface);
339 if (err != Rosen::DMError::DM_OK) {
340 SHARING_LOGE("Set surface for virtual screen failed, screenId:%{public}" PRIu64 "!", screenId_);
341 return ERR_GENERAL_ERROR;
342 }
343 return ERR_OK;
344 }
345
RemoveScreenFromGroup() const346 void VideoSourceScreen::RemoveScreenFromGroup() const
347 {
348 SHARING_LOGD("trace.");
349 if (screenId_ != SCREEN_ID_INVALID) {
350 SHARING_LOGE("Failed, invalid screenId!");
351 }
352 SHARING_LOGD("Remove screen from group, screenId: %{publid}" PRIu64 ".", screenId_);
353 std::vector<uint64_t> screenIds;
354 screenIds.push_back(screenId_);
355 Rosen::DMError err = Rosen::ScreenManager::GetInstance().RemoveVirtualScreenFromGroup(screenIds);
356 if (err != Rosen::DMError::DM_OK) {
357 SHARING_LOGE("Remove screen from group failed, screenId:%{public}" PRIu64 "!", screenId_);
358 }
359 }
360 } // namespace Sharing
361 } // namespace OHOS
362