• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/frontend/webrtc/display_handler.h"
18 
19 #include <chrono>
20 #include <functional>
21 #include <memory>
22 
23 #include <libyuv.h>
24 
25 namespace cuttlefish {
DisplayHandler(std::shared_ptr<webrtc_streaming::VideoSink> display_sink,ScreenConnector & screen_connector)26 DisplayHandler::DisplayHandler(
27     std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
28     ScreenConnector& screen_connector)
29     : display_sink_(display_sink), screen_connector_(screen_connector) {
30   screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
31 }
32 
GetScreenConnectorCallback()33 DisplayHandler::GenerateProcessedFrameCallback DisplayHandler::GetScreenConnectorCallback() {
34     // only to tell the producer how to create a ProcessedFrame to cache into the queue
35     DisplayHandler::GenerateProcessedFrameCallback callback =
36         [](std::uint32_t display_number, std::uint8_t* frame_pixels,
37            WebRtcScProcessedFrame& processed_frame) {
38           processed_frame.display_number_ = display_number;
39           // TODO(171305898): handle multiple displays.
40           if (display_number != 0) {
41             // BUG 186580833: display_number comes from surface_id in crosvm
42             // create_surface from virtio_gpu.rs set_scanout.  We cannot use it as
43             // the display number. Either crosvm virtio-gpu is incorrectly ignoring
44             // scanout id and instead using a monotonically increasing surface id
45             // number as the scanout resource is replaced over time, or frontend code
46             // here is incorrectly assuming  surface id == display id.
47             display_number = 0;
48           }
49           const int display_w =
50               ScreenConnectorInfo::ScreenWidth(display_number);
51           const int display_h =
52               ScreenConnectorInfo::ScreenHeight(display_number);
53           const int display_stride_bytes =
54               ScreenConnectorInfo::ScreenStrideBytes(display_number);
55           processed_frame.display_number_ = display_number;
56           processed_frame.buf_ =
57               std::make_unique<CvdVideoFrameBuffer>(display_w, display_h);
58           libyuv::ABGRToI420(
59               frame_pixels, display_stride_bytes, processed_frame.buf_->DataY(),
60               processed_frame.buf_->StrideY(), processed_frame.buf_->DataU(),
61               processed_frame.buf_->StrideU(), processed_frame.buf_->DataV(),
62               processed_frame.buf_->StrideV(), display_w, display_h);
63           processed_frame.is_success_ = true;
64         };
65     return callback;
66 }
67 
Loop()68 [[noreturn]] void DisplayHandler::Loop() {
69   for (;;) {
70     auto processed_frame = screen_connector_.OnNextFrame();
71     // processed_frame has display number from the guest
72     {
73       std::lock_guard<std::mutex> lock(last_buffer_mutex_);
74       std::shared_ptr<CvdVideoFrameBuffer> buffer = std::move(processed_frame.buf_);
75       last_buffer_ =
76           std::static_pointer_cast<webrtc_streaming::VideoFrameBuffer>(buffer);
77     }
78     if (processed_frame.is_success_) {
79       SendLastFrame();
80     }
81   }
82 }
83 
SendLastFrame()84 void DisplayHandler::SendLastFrame() {
85   std::shared_ptr<webrtc_streaming::VideoFrameBuffer> buffer;
86   {
87     std::lock_guard<std::mutex> lock(last_buffer_mutex_);
88     buffer = last_buffer_;
89   }
90   if (!buffer) {
91     // If a connection request arrives before the first frame is available don't
92     // send any frame.
93     return;
94   }
95   {
96     // SendLastFrame can be called from multiple threads simultaneously, locking
97     // here avoids injecting frames with the timestamps in the wrong order.
98     std::lock_guard<std::mutex> lock(next_frame_mutex_);
99     int64_t time_stamp =
100         std::chrono::duration_cast<std::chrono::microseconds>(
101             std::chrono::system_clock::now().time_since_epoch())
102             .count();
103     display_sink_->OnFrame(buffer, time_stamp);
104   }
105 }
106 
IncClientCount()107 void DisplayHandler::IncClientCount() {
108   client_count_++;
109   if (client_count_ == 1) {
110     screen_connector_.ReportClientsConnected(true);
111   }
112 }
113 
DecClientCount()114 void DisplayHandler::DecClientCount() {
115   client_count_--;
116   if (client_count_ == 0) {
117     screen_connector_.ReportClientsConnected(false);
118   }
119 }
120 
121 }  // namespace cuttlefish
122