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 #include "host/frontend/webrtc/libdevice/streamer.h"
26
27 namespace cuttlefish {
DisplayHandler(webrtc_streaming::Streamer & streamer,ScreenConnector & screen_connector)28 DisplayHandler::DisplayHandler(webrtc_streaming::Streamer& streamer,
29 ScreenConnector& screen_connector)
30 : streamer_(streamer), screen_connector_(screen_connector) {
31 screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
32 screen_connector_.SetDisplayEventCallback([this](const DisplayEvent& event) {
33 std::visit(
34 [this](auto&& e) {
35 using T = std::decay_t<decltype(e)>;
36 if constexpr (std::is_same_v<DisplayCreatedEvent, T>) {
37 LOG(VERBOSE) << "Display:" << e.display_number << " created "
38 << " w:" << e.display_width
39 << " h:" << e.display_height;
40
41 const auto display_number = e.display_number;
42 const std::string display_id =
43 "display_" + std::to_string(e.display_number);
44 auto display = streamer_.AddDisplay(display_id, e.display_width,
45 e.display_height, 160, true);
46 if (!display) {
47 LOG(ERROR) << "Failed to create display.";
48 return;
49 }
50
51 display_sinks_[display_number] = display;
52 } else if constexpr (std::is_same_v<DisplayDestroyedEvent, T>) {
53 LOG(VERBOSE) << "Display:" << e.display_number << " destroyed.";
54
55 const auto display_number = e.display_number;
56 const auto display_id =
57 "display_" + std::to_string(e.display_number);
58 streamer_.RemoveDisplay(display_id);
59 display_sinks_.erase(display_number);
60 } else {
61 static_assert("Unhandled display event.");
62 }
63 },
64 event);
65 });
66 }
67
GetScreenConnectorCallback()68 DisplayHandler::GenerateProcessedFrameCallback DisplayHandler::GetScreenConnectorCallback() {
69 // only to tell the producer how to create a ProcessedFrame to cache into the queue
70 DisplayHandler::GenerateProcessedFrameCallback callback =
71 [](std::uint32_t display_number, std::uint32_t frame_width,
72 std::uint32_t frame_height, std::uint32_t frame_stride_bytes,
73 std::uint8_t* frame_pixels,
74 WebRtcScProcessedFrame& processed_frame) {
75 processed_frame.display_number_ = display_number;
76 processed_frame.buf_ =
77 std::make_unique<CvdVideoFrameBuffer>(frame_width, frame_height);
78 libyuv::ABGRToI420(
79 frame_pixels, frame_stride_bytes, processed_frame.buf_->DataY(),
80 processed_frame.buf_->StrideY(), processed_frame.buf_->DataU(),
81 processed_frame.buf_->StrideU(), processed_frame.buf_->DataV(),
82 processed_frame.buf_->StrideV(), frame_width, frame_height);
83 processed_frame.is_success_ = true;
84 };
85 return callback;
86 }
87
Loop()88 [[noreturn]] void DisplayHandler::Loop() {
89 for (;;) {
90 auto processed_frame = screen_connector_.OnNextFrame();
91 // processed_frame has display number from the guest
92 {
93 std::lock_guard<std::mutex> lock(last_buffer_mutex_);
94 std::shared_ptr<CvdVideoFrameBuffer> buffer = std::move(processed_frame.buf_);
95 last_buffer_display_ = processed_frame.display_number_;
96 last_buffer_ =
97 std::static_pointer_cast<webrtc_streaming::VideoFrameBuffer>(buffer);
98 }
99 if (processed_frame.is_success_) {
100 SendLastFrame();
101 }
102 }
103 }
104
SendLastFrame()105 void DisplayHandler::SendLastFrame() {
106 std::shared_ptr<webrtc_streaming::VideoFrameBuffer> buffer;
107 std::uint32_t buffer_display;
108 {
109 std::lock_guard<std::mutex> lock(last_buffer_mutex_);
110 buffer = last_buffer_;
111 buffer_display = last_buffer_display_;
112 }
113 if (!buffer) {
114 // If a connection request arrives before the first frame is available don't
115 // send any frame.
116 return;
117 }
118 {
119 // SendLastFrame can be called from multiple threads simultaneously, locking
120 // here avoids injecting frames with the timestamps in the wrong order.
121 std::lock_guard<std::mutex> lock(next_frame_mutex_);
122 int64_t time_stamp =
123 std::chrono::duration_cast<std::chrono::microseconds>(
124 std::chrono::system_clock::now().time_since_epoch())
125 .count();
126
127 auto it = display_sinks_.find(buffer_display);
128 if (it != display_sinks_.end()) {
129 it->second->OnFrame(buffer, time_stamp);
130 }
131 }
132 }
133 } // namespace cuttlefish
134