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 <drm/drm_fourcc.h>
24 #include <libyuv.h>
25
26 #include "host/frontend/webrtc/libdevice/streamer.h"
27
28 namespace cuttlefish {
29
DisplayHandler(webrtc_streaming::Streamer & streamer,int wayland_socket_fd,bool wayland_frames_are_rgba)30 DisplayHandler::DisplayHandler(webrtc_streaming::Streamer& streamer,
31 int wayland_socket_fd,
32 bool wayland_frames_are_rgba)
33 : streamer_(streamer) {
34 int wayland_fd = fcntl(wayland_socket_fd, F_DUPFD_CLOEXEC, 3);
35 CHECK(wayland_fd != -1) << "Unable to dup server, errno " << errno;
36 close(wayland_socket_fd);
37 wayland_server_ = std::make_unique<wayland::WaylandServer>(
38 wayland_fd, wayland_frames_are_rgba);
39 wayland_server_->SetDisplayEventCallback([this](const DisplayEvent& event) {
40 std::visit(
41 [this](auto&& e) {
42 using T = std::decay_t<decltype(e)>;
43 if constexpr (std::is_same_v<DisplayCreatedEvent, T>) {
44 LOG(VERBOSE) << "Display:" << e.display_number << " created "
45 << " w:" << e.display_width
46 << " h:" << e.display_height;
47
48 const auto display_number = e.display_number;
49 const std::string display_id =
50 "display_" + std::to_string(e.display_number);
51 auto display = streamer_.AddDisplay(display_id, e.display_width,
52 e.display_height, 160, true);
53 if (!display) {
54 LOG(ERROR) << "Failed to create display.";
55 return;
56 }
57
58 display_sinks_[display_number] = display;
59 } else if constexpr (std::is_same_v<DisplayDestroyedEvent, T>) {
60 LOG(VERBOSE) << "Display:" << e.display_number << " destroyed.";
61
62 const auto display_number = e.display_number;
63 const auto display_id =
64 "display_" + std::to_string(e.display_number);
65 streamer_.RemoveDisplay(display_id);
66 display_sinks_.erase(display_number);
67 } else {
68 static_assert("Unhandled display event.");
69 }
70 },
71 event);
72 });
73 wayland_server_->SetFrameCallback([this](
74 std::uint32_t display_number, //
75 std::uint32_t frame_width, //
76 std::uint32_t frame_height, //
77 std::uint32_t frame_fourcc_format, //
78 std::uint32_t frame_stride_bytes, //
79 std::uint8_t* frame_pixels) {
80 auto buf = std::make_shared<CvdVideoFrameBuffer>(frame_width, frame_height);
81 if (frame_fourcc_format == DRM_FORMAT_ARGB8888 ||
82 frame_fourcc_format == DRM_FORMAT_XRGB8888) {
83 libyuv::ARGBToI420(frame_pixels, frame_stride_bytes, buf->DataY(),
84 buf->StrideY(), buf->DataU(), buf->StrideU(),
85 buf->DataV(), buf->StrideV(), frame_width,
86 frame_height);
87 } else if (frame_fourcc_format == DRM_FORMAT_ABGR8888 ||
88 frame_fourcc_format == DRM_FORMAT_XBGR8888) {
89 libyuv::ABGRToI420(frame_pixels, frame_stride_bytes, buf->DataY(),
90 buf->StrideY(), buf->DataU(), buf->StrideU(),
91 buf->DataV(), buf->StrideV(), frame_width,
92 frame_height);
93 } else {
94 LOG(ERROR) << "Unhandled frame format: " << frame_fourcc_format;
95 return;
96 }
97
98 {
99 std::lock_guard<std::mutex> lock(last_buffer_mutex_);
100 display_last_buffers_[display_number] =
101 std::static_pointer_cast<webrtc_streaming::VideoFrameBuffer>(buf);
102 }
103
104 SendLastFrame(display_number);
105 });
106 }
107
SendLastFrame(std::optional<uint32_t> display_number)108 void DisplayHandler::SendLastFrame(std::optional<uint32_t> display_number) {
109 std::map<uint32_t, std::shared_ptr<webrtc_streaming::VideoFrameBuffer>>
110 buffers;
111 {
112 std::lock_guard<std::mutex> lock(last_buffer_mutex_);
113 if (display_number) {
114 // Resend the last buffer for a single display.
115 auto last_buffer_it = display_last_buffers_.find(*display_number);
116 if (last_buffer_it == display_last_buffers_.end()) {
117 return;
118 }
119 auto& last_buffer = last_buffer_it->second;
120 if (!last_buffer) {
121 return;
122 }
123 buffers[*display_number] = last_buffer;
124 } else {
125 // Resend the last buffer for all displays.
126 buffers = display_last_buffers_;
127 }
128 }
129 if (buffers.empty()) {
130 // If a connection request arrives before the first frame is available don't
131 // send any frame.
132 return;
133 }
134 {
135 // SendLastFrame can be called from multiple threads simultaneously, locking
136 // here avoids injecting frames with the timestamps in the wrong order.
137 std::lock_guard<std::mutex> lock(next_frame_mutex_);
138 int64_t time_stamp =
139 std::chrono::duration_cast<std::chrono::microseconds>(
140 std::chrono::system_clock::now().time_since_epoch())
141 .count();
142
143 for (const auto& [display_number, buffer] : buffers) {
144 auto it = display_sinks_.find(display_number);
145 if (it != display_sinks_.end()) {
146 it->second->OnFrame(buffer, time_stamp);
147 }
148 }
149 }
150 }
151
152 } // namespace cuttlefish
153