This reverts commit 726992d7a4722b8a283d797d04432d0c6335ca96. Reason for revert: Relanding with original errors fixed (tested by building the patch locally against Chromium) This change no longer attempts to migrate the display size protocol from fuchsia.ui.scenic.Scenic/GetDisplayInfo to fuchsia.ui.display.singleton.Info/GetMetrics because the latter API was introduced in Fuchsia API 12, which is not yet supported in Chrome (hence some of the build errors causing the revert). Original change's description: > Revert "[fuchsia] remove Scenic and GFX dependencies in DesktopCapturer" > > This reverts commit fe5be2eb4ff8dccd96257fb8cbf32500c636c358. > > Reason for revert: This breaks the WebRTC roll into Chromium: > > - https://chromium-review.googlesource.com/c/chromium/src/+/4688561 > - https://ci.chromium.org/ui/p/chromium/builders/try/fuchsia-binary-size/399140/overview > > Error: > > [4273/4389] CXX obj/third_party/webrtc/modules/desktop_capture/desktop_capture/screen_capturer_fuchsia.o > FAILED: obj/third_party/webrtc/modules/desktop_capture/desktop_capture/screen_capturer_fuchsia.o > ../../buildtools/reclient/rewrapper -cfg=../../buildtools/reclient_cfgs/chromium-browser-clang/rewra...(too long) > ../../third_party/webrtc/modules/desktop_capture/screen_capturer_fuchsia.cc:59:10: error: use of undeclared identifier 'capturer' > 59 | return capturer(new ScreenCapturerFuchsia()); > | ^ > ../../third_party/webrtc/modules/desktop_capture/screen_capturer_fuchsia.cc:199:36: error: no type named 'InfoSyncPtr' in namespace 'fuchsia::ui::display::singleton' > > Original change's description: > > [fuchsia] remove Scenic and GFX dependencies in DesktopCapturer > > > > We previously used: > > - fuchsia.ui.scenic.Scenic/UsesFlatland to determine whether to use > > Flatland; from now on it should always be the case, so this check is > > no longer necessary. > > - fuchsia.ui.scenic.Scenic/GetDisplayInfo to get > > fuchsia.ui.gfx.DisplayInfo. This has been migrated to > > fuchsia.ui.display.singleton.Info/GetMetrics and > > fuchsia.ui.display.singleton.Metrics. > > > > Bug: fuchsia:100303 > > Change-Id: I147da9ffdf0ca49e1c5bde5d188e434fc660becc > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311860 > > Reviewed-by: Emircan Uysaler <emircan@google.com> > > Reviewed-by: Alexander Cooper <alcooper@chromium.org> > > Commit-Queue: Caroline Liu <carolineliu@google.com> > > Cr-Commit-Position: refs/heads/main@{#40432} > > Bug: fuchsia:100303, b/291393959 > Change-Id: Iae70e568a8c9819e40e48069af8cea0d4ef2b6c5 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311801 > Owners-Override: Mirko Bonadei <mbonadei@webrtc.org> > Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com> > Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#40436} Bug: fuchsia:100303, b/291393959 Change-Id: Icb7074ac86c1804ab2bdf809ea1496539ee2bf80 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/312000 Commit-Queue: Caroline Liu <carolineliu@google.com> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Alexander Cooper <alcooper@chromium.org> Cr-Commit-Position: refs/heads/main@{#40452}
392 lines
14 KiB
C++
392 lines
14 KiB
C++
/*
|
|
* Copyright 2022 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/desktop_capture/screen_capturer_fuchsia.h"
|
|
|
|
#include <fuchsia/sysmem/cpp/fidl.h>
|
|
#include <fuchsia/ui/composition/cpp/fidl.h>
|
|
#include <fuchsia/ui/scenic/cpp/fidl.h>
|
|
#include <lib/sys/cpp/component_context.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h"
|
|
#include "modules/desktop_capture/desktop_capture_options.h"
|
|
#include "modules/desktop_capture/desktop_capture_types.h"
|
|
#include "modules/desktop_capture/desktop_capturer.h"
|
|
#include "modules/desktop_capture/desktop_frame.h"
|
|
#include "modules/desktop_capture/desktop_geometry.h"
|
|
#include "modules/desktop_capture/fallback_desktop_capturer_wrapper.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/numerics/divide_round.h"
|
|
#include "rtc_base/time_utils.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
static constexpr uint32_t kMinBufferCount = 2;
|
|
static constexpr uint32_t kFuchsiaBytesPerPixel = 4;
|
|
static constexpr DesktopCapturer::SourceId kFuchsiaScreenId = 1;
|
|
// 500 milliseconds
|
|
static constexpr zx::duration kEventDelay = zx::msec(500);
|
|
static constexpr fuchsia::sysmem::ColorSpaceType kSRGBColorSpace =
|
|
fuchsia::sysmem::ColorSpaceType::SRGB;
|
|
static constexpr fuchsia::sysmem::PixelFormatType kBGRA32PixelFormatType =
|
|
fuchsia::sysmem::PixelFormatType::BGRA32;
|
|
|
|
// Round |value| up to the closest multiple of |multiple|
|
|
size_t RoundUpToMultiple(size_t value, size_t multiple) {
|
|
return DivideRoundUp(value, multiple) * multiple;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
|
|
const DesktopCaptureOptions& options) {
|
|
std::unique_ptr<ScreenCapturerFuchsia> capturer(new ScreenCapturerFuchsia());
|
|
return capturer;
|
|
}
|
|
|
|
ScreenCapturerFuchsia::ScreenCapturerFuchsia()
|
|
: component_context_(sys::ComponentContext::Create()) {}
|
|
|
|
ScreenCapturerFuchsia::~ScreenCapturerFuchsia() {
|
|
// unmap virtual memory mapped pointers
|
|
uint32_t virt_mem_bytes =
|
|
buffer_collection_info_.settings.buffer_settings.size_bytes;
|
|
for (uint32_t buffer_index = 0;
|
|
buffer_index < buffer_collection_info_.buffer_count; buffer_index++) {
|
|
uintptr_t address =
|
|
reinterpret_cast<uintptr_t>(virtual_memory_mapped_addrs_[buffer_index]);
|
|
zx_status_t status = zx::vmar::root_self()->unmap(address, virt_mem_bytes);
|
|
RTC_DCHECK(status == ZX_OK);
|
|
}
|
|
}
|
|
|
|
void ScreenCapturerFuchsia::Start(Callback* callback) {
|
|
RTC_DCHECK(!callback_);
|
|
RTC_DCHECK(callback);
|
|
callback_ = callback;
|
|
|
|
fatal_error_ = false;
|
|
|
|
SetupBuffers();
|
|
}
|
|
|
|
void ScreenCapturerFuchsia::CaptureFrame() {
|
|
if (fatal_error_) {
|
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
|
return;
|
|
}
|
|
|
|
int64_t capture_start_time_nanos = rtc::TimeNanos();
|
|
|
|
zx::event event;
|
|
zx::event dup;
|
|
zx_status_t status = zx::event::create(0, &event);
|
|
if (status != ZX_OK) {
|
|
RTC_LOG(LS_ERROR) << "Failed to create event: " << status;
|
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
|
return;
|
|
}
|
|
event.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup);
|
|
|
|
fuchsia::ui::composition::GetNextFrameArgs next_frame_args;
|
|
next_frame_args.set_event(std::move(dup));
|
|
|
|
fuchsia::ui::composition::ScreenCapture_GetNextFrame_Result result;
|
|
screen_capture_->GetNextFrame(std::move(next_frame_args), &result);
|
|
if (result.is_err()) {
|
|
RTC_LOG(LS_ERROR) << "fuchsia.ui.composition.GetNextFrame() failed: "
|
|
<< result.err() << "\n";
|
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
|
return;
|
|
}
|
|
|
|
status = event.wait_one(ZX_EVENT_SIGNALED, zx::deadline_after(kEventDelay),
|
|
nullptr);
|
|
if (status != ZX_OK) {
|
|
RTC_LOG(LS_ERROR) << "Timed out waiting for ScreenCapture to render frame: "
|
|
<< status;
|
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
|
return;
|
|
}
|
|
uint32_t buffer_index = result.response().buffer_id();
|
|
|
|
// TODO(bugs.webrtc.org/14097): Use SharedMemoryDesktopFrame and
|
|
// ScreenCaptureFrameQueue
|
|
std::unique_ptr<BasicDesktopFrame> frame(
|
|
new BasicDesktopFrame(DesktopSize(width_, height_)));
|
|
|
|
uint32_t pixels_per_row = GetPixelsPerRow(
|
|
buffer_collection_info_.settings.image_format_constraints);
|
|
uint32_t stride = kFuchsiaBytesPerPixel * pixels_per_row;
|
|
frame->CopyPixelsFrom(virtual_memory_mapped_addrs_[buffer_index], stride,
|
|
DesktopRect::MakeWH(width_, height_));
|
|
// Mark the whole screen as having been updated.
|
|
frame->mutable_updated_region()->SetRect(
|
|
DesktopRect::MakeWH(width_, height_));
|
|
|
|
fuchsia::ui::composition::ScreenCapture_ReleaseFrame_Result release_result;
|
|
screen_capture_->ReleaseFrame(buffer_index, &release_result);
|
|
if (release_result.is_err()) {
|
|
RTC_LOG(LS_ERROR) << "fuchsia.ui.composition.ReleaseFrame() failed: "
|
|
<< release_result.err();
|
|
}
|
|
|
|
int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) /
|
|
rtc::kNumNanosecsPerMillisec;
|
|
frame->set_capture_time_ms(capture_time_ms);
|
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
|
}
|
|
|
|
bool ScreenCapturerFuchsia::GetSourceList(SourceList* screens) {
|
|
RTC_DCHECK(screens->size() == 0);
|
|
// Fuchsia only supports single monitor display at this point
|
|
screens->push_back({kFuchsiaScreenId, std::string("Fuchsia monitor")});
|
|
return true;
|
|
}
|
|
|
|
bool ScreenCapturerFuchsia::SelectSource(SourceId id) {
|
|
if (id == kFuchsiaScreenId || id == kFullDesktopScreenId) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fuchsia::sysmem::BufferCollectionConstraints
|
|
ScreenCapturerFuchsia::GetBufferConstraints() {
|
|
fuchsia::sysmem::BufferCollectionConstraints constraints;
|
|
constraints.usage.cpu =
|
|
fuchsia::sysmem::cpuUsageRead | fuchsia::sysmem::cpuUsageWrite;
|
|
constraints.min_buffer_count = kMinBufferCount;
|
|
|
|
constraints.has_buffer_memory_constraints = true;
|
|
constraints.buffer_memory_constraints.ram_domain_supported = true;
|
|
constraints.buffer_memory_constraints.cpu_domain_supported = true;
|
|
|
|
constraints.image_format_constraints_count = 1;
|
|
fuchsia::sysmem::ImageFormatConstraints& image_constraints =
|
|
constraints.image_format_constraints[0];
|
|
image_constraints.color_spaces_count = 1;
|
|
image_constraints.color_space[0] =
|
|
fuchsia::sysmem::ColorSpace{.type = kSRGBColorSpace};
|
|
image_constraints.pixel_format.type = kBGRA32PixelFormatType;
|
|
image_constraints.pixel_format.has_format_modifier = true;
|
|
image_constraints.pixel_format.format_modifier.value =
|
|
fuchsia::sysmem::FORMAT_MODIFIER_LINEAR;
|
|
|
|
image_constraints.required_min_coded_width = width_;
|
|
image_constraints.required_min_coded_height = height_;
|
|
image_constraints.required_max_coded_width = width_;
|
|
image_constraints.required_max_coded_height = height_;
|
|
|
|
image_constraints.bytes_per_row_divisor = kFuchsiaBytesPerPixel;
|
|
|
|
return constraints;
|
|
}
|
|
|
|
void ScreenCapturerFuchsia::SetupBuffers() {
|
|
fuchsia::ui::scenic::ScenicSyncPtr scenic;
|
|
zx_status_t status = component_context_->svc()->Connect(scenic.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to connect to Scenic: " << status;
|
|
return;
|
|
}
|
|
|
|
fuchsia::ui::gfx::DisplayInfo display_info;
|
|
status = scenic->GetDisplayInfo(&display_info);
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to connect to get display dimensions: "
|
|
<< status;
|
|
return;
|
|
}
|
|
width_ = display_info.width_in_px;
|
|
height_ = display_info.height_in_px;
|
|
|
|
status = component_context_->svc()->Connect(sysmem_allocator_.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to connect to Sysmem Allocator: " << status;
|
|
return;
|
|
}
|
|
|
|
fuchsia::sysmem::BufferCollectionTokenSyncPtr sysmem_token;
|
|
status =
|
|
sysmem_allocator_->AllocateSharedCollection(sysmem_token.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "fuchsia.sysmem.Allocator.AllocateSharedCollection() failed: "
|
|
<< status;
|
|
return;
|
|
}
|
|
|
|
fuchsia::sysmem::BufferCollectionTokenSyncPtr flatland_token;
|
|
status = sysmem_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
|
|
flatland_token.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "fuchsia.sysmem.BufferCollectionToken.Duplicate() failed: "
|
|
<< status;
|
|
return;
|
|
}
|
|
|
|
status = sysmem_token->Sync();
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "fuchsia.sysmem.BufferCollectionToken.Sync() failed: "
|
|
<< status;
|
|
return;
|
|
}
|
|
|
|
status = sysmem_allocator_->BindSharedCollection(std::move(sysmem_token),
|
|
collection_.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "fuchsia.sysmem.Allocator.BindSharedCollection() failed: " << status;
|
|
return;
|
|
}
|
|
|
|
status = collection_->SetConstraints(/*has_constraints=*/true,
|
|
GetBufferConstraints());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "fuchsia.sysmem.BufferCollection.SetConstraints() failed: "
|
|
<< status;
|
|
return;
|
|
}
|
|
|
|
fuchsia::ui::composition::BufferCollectionImportToken import_token;
|
|
fuchsia::ui::composition::BufferCollectionExportToken export_token;
|
|
status = zx::eventpair::create(0, &export_token.value, &import_token.value);
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "Failed to create BufferCollection import and export tokens: "
|
|
<< status;
|
|
return;
|
|
}
|
|
|
|
status = component_context_->svc()->Connect(flatland_allocator_.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to connect to Flatland Allocator: " << status;
|
|
return;
|
|
}
|
|
|
|
fuchsia::ui::composition::RegisterBufferCollectionArgs buffer_collection_args;
|
|
buffer_collection_args.set_export_token(std::move(export_token));
|
|
buffer_collection_args.set_buffer_collection_token(std::move(flatland_token));
|
|
buffer_collection_args.set_usage(
|
|
fuchsia::ui::composition::RegisterBufferCollectionUsage::SCREENSHOT);
|
|
|
|
fuchsia::ui::composition::Allocator_RegisterBufferCollection_Result
|
|
buffer_collection_result;
|
|
flatland_allocator_->RegisterBufferCollection(
|
|
std::move(buffer_collection_args), &buffer_collection_result);
|
|
if (buffer_collection_result.is_err()) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "fuchsia.ui.composition.Allocator."
|
|
"RegisterBufferCollection() failed.";
|
|
return;
|
|
}
|
|
|
|
zx_status_t allocation_status;
|
|
status = collection_->WaitForBuffersAllocated(&allocation_status,
|
|
&buffer_collection_info_);
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to wait for buffer collection info: "
|
|
<< status;
|
|
return;
|
|
}
|
|
if (allocation_status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to allocate buffer collection: " << status;
|
|
return;
|
|
}
|
|
status = collection_->Close();
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to close buffer collection token: " << status;
|
|
return;
|
|
}
|
|
|
|
status = component_context_->svc()->Connect(screen_capture_.NewRequest());
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to connect to Screen Capture: " << status;
|
|
return;
|
|
}
|
|
|
|
// Configure buffers in ScreenCapture client.
|
|
fuchsia::ui::composition::ScreenCaptureConfig configure_args;
|
|
configure_args.set_import_token(std::move(import_token));
|
|
configure_args.set_buffer_count(buffer_collection_info_.buffer_count);
|
|
configure_args.set_size({width_, height_});
|
|
|
|
fuchsia::ui::composition::ScreenCapture_Configure_Result configure_result;
|
|
screen_capture_->Configure(std::move(configure_args), &configure_result);
|
|
if (configure_result.is_err()) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR)
|
|
<< "fuchsia.ui.composition.ScreenCapture.Configure() failed: "
|
|
<< configure_result.err();
|
|
return;
|
|
}
|
|
|
|
// We have a collection of virtual memory objects which the ScreenCapture
|
|
// client will write the frame data to when requested. We map each of these
|
|
// onto a pointer stored in virtual_memory_mapped_addrs_ which we can use to
|
|
// access this data.
|
|
uint32_t virt_mem_bytes =
|
|
buffer_collection_info_.settings.buffer_settings.size_bytes;
|
|
RTC_DCHECK(virt_mem_bytes > 0);
|
|
for (uint32_t buffer_index = 0;
|
|
buffer_index < buffer_collection_info_.buffer_count; buffer_index++) {
|
|
const zx::vmo& virt_mem = buffer_collection_info_.buffers[buffer_index].vmo;
|
|
virtual_memory_mapped_addrs_[buffer_index] = nullptr;
|
|
auto status = zx::vmar::root_self()->map(
|
|
ZX_VM_PERM_READ, /*vmar_offset*/ 0, virt_mem,
|
|
/*vmo_offset*/ 0, virt_mem_bytes,
|
|
reinterpret_cast<uintptr_t*>(
|
|
&virtual_memory_mapped_addrs_[buffer_index]));
|
|
if (status != ZX_OK) {
|
|
fatal_error_ = true;
|
|
RTC_LOG(LS_ERROR) << "Failed to map virtual memory: " << status;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t ScreenCapturerFuchsia::GetPixelsPerRow(
|
|
const fuchsia::sysmem::ImageFormatConstraints& constraints) {
|
|
uint32_t stride = RoundUpToMultiple(
|
|
std::max(constraints.min_bytes_per_row, width_ * kFuchsiaBytesPerPixel),
|
|
constraints.bytes_per_row_divisor);
|
|
uint32_t pixels_per_row = stride / kFuchsiaBytesPerPixel;
|
|
|
|
return pixels_per_row;
|
|
}
|
|
|
|
} // namespace webrtc
|