• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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