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