Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This class is similar to DesktopCaptureDeviceMac. Create a common base class, IOSurfaceCaptureDeviceBase, with the shared functionality. Add ScreenCaptureKitDeviceMac, and a feature kScreenCaptureKitMac that it's gated on. Bug: 1309653 Change-Id: Ic888bcb0c745a50574e82e645dc50fd41836542d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3544199 Reviewed-by: Robert Sesek <rsesek@chromium.org> Reviewed-by: Elad Alon <eladalon@chromium.org> Commit-Queue: ccameron chromium <ccameron@chromium.org> Cr-Commit-Position: refs/heads/main@{#985638}
- Loading branch information
1 parent
7024fdf
commit 34c9f76
Showing
11 changed files
with
626 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
content/browser/media/capture/io_surface_capture_device_base_mac.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "content/browser/media/capture/io_surface_capture_device_base_mac.h" | ||
|
||
#include "media/base/video_util.h" | ||
#include "media/capture/content/capture_resolution_chooser.h" | ||
|
||
namespace content { | ||
|
||
namespace { | ||
|
||
float ComputeMinFrameRate(float requested_frame_rate) { | ||
// Set a minimum frame rate of 5 fps, unless the requested frame rate is | ||
// even lower. | ||
constexpr float kMinFrameRate = 5.f; | ||
|
||
// Don't send frames at more than 80% the requested rate, because doing so | ||
// can stochastically toggle between repeated and new frames. | ||
constexpr float kRequestedFrameRateFactor = 0.8f; | ||
|
||
return std::min(requested_frame_rate * kRequestedFrameRateFactor, | ||
kMinFrameRate); | ||
} | ||
|
||
} // namespace | ||
|
||
IOSurfaceCaptureDeviceBase::IOSurfaceCaptureDeviceBase() = default; | ||
IOSurfaceCaptureDeviceBase::~IOSurfaceCaptureDeviceBase() = default; | ||
|
||
void IOSurfaceCaptureDeviceBase::AllocateAndStart( | ||
const media::VideoCaptureParams& params, | ||
std::unique_ptr<Client> client) { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
DCHECK(client && !client_); | ||
client_ = std::move(client); | ||
capture_params_ = params; | ||
min_frame_rate_ = | ||
ComputeMinFrameRate(capture_params_.requested_format.frame_rate); | ||
|
||
OnStart(); | ||
} | ||
|
||
void IOSurfaceCaptureDeviceBase::StopAndDeAllocate() { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
min_frame_rate_enforcement_timer_.reset(); | ||
weak_factory_base_.InvalidateWeakPtrs(); | ||
|
||
OnStop(); | ||
} | ||
|
||
void IOSurfaceCaptureDeviceBase::OnReceivedIOSurfaceFromStream( | ||
gfx::ScopedInUseIOSurface io_surface, | ||
const media::VideoCaptureFormat& capture_format) { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
last_received_io_surface_ = std::move(io_surface); | ||
last_received_capture_format_ = capture_format; | ||
|
||
// Immediately send the new frame to the client. | ||
SendLastReceivedIOSurfaceToClient(); | ||
} | ||
|
||
void IOSurfaceCaptureDeviceBase::SendLastReceivedIOSurfaceToClient() { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
|
||
// Package `last_received_io_surface_` as a GpuMemoryBuffer. | ||
gfx::GpuMemoryBufferHandle handle; | ||
handle.id = gfx::GpuMemoryBufferHandle::kInvalidId; | ||
handle.type = gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER; | ||
handle.io_surface.reset(last_received_io_surface_, | ||
base::scoped_policy::RETAIN); | ||
|
||
const auto now = base::TimeTicks::Now(); | ||
if (first_frame_time_.is_null()) | ||
first_frame_time_ = now; | ||
|
||
client_->OnIncomingCapturedExternalBuffer( | ||
media::CapturedExternalVideoBuffer(std::move(handle), | ||
last_received_capture_format_, | ||
gfx::ColorSpace::CreateREC709()), | ||
{}, now, now - first_frame_time_); | ||
|
||
// Reset `min_frame_rate_enforcement_timer_`. | ||
if (!min_frame_rate_enforcement_timer_) { | ||
min_frame_rate_enforcement_timer_ = std::make_unique<base::RepeatingTimer>( | ||
FROM_HERE, base::Seconds(1 / min_frame_rate_), | ||
base::BindRepeating( | ||
&IOSurfaceCaptureDeviceBase::SendLastReceivedIOSurfaceToClient, | ||
weak_factory_base_.GetWeakPtr())); | ||
} | ||
min_frame_rate_enforcement_timer_->Reset(); | ||
} | ||
|
||
void IOSurfaceCaptureDeviceBase::ComputeFrameSizeAndDestRect( | ||
const gfx::Size& source_size, | ||
gfx::Size& frame_size, | ||
gfx::RectF& dest_rect_in_frame) const { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
|
||
// Compute the destination frame size using CaptureResolutionChooser. | ||
const auto constraints = capture_params_.SuggestConstraints(); | ||
{ | ||
media::CaptureResolutionChooser resolution_chooser; | ||
resolution_chooser.SetConstraints(constraints.min_frame_size, | ||
constraints.max_frame_size, | ||
constraints.fixed_aspect_ratio); | ||
resolution_chooser.SetSourceSize(source_size); | ||
// Ensure that the resulting frame size has an even width and height. This | ||
// matches the behavior of DesktopCaptureDevice. | ||
frame_size = gfx::Size(resolution_chooser.capture_size().width() & ~1, | ||
resolution_chooser.capture_size().height() & ~1); | ||
if (frame_size.IsEmpty()) | ||
frame_size = gfx::Size(2, 2); | ||
} | ||
|
||
// Compute the rectangle to blit into. | ||
if (constraints.fixed_aspect_ratio) { | ||
dest_rect_in_frame = gfx::RectF(media::ComputeLetterboxRegionForI420( | ||
gfx::Rect(frame_size), source_size)); | ||
// If the target rectangle is not exactly the full frame, then out-set | ||
// the region by a tiny amount. This works around a bug wherein a green | ||
// line appears on the left side of the content. | ||
// https://crbug.com/1267655 | ||
if (dest_rect_in_frame != gfx::RectF(gfx::SizeF(frame_size))) | ||
dest_rect_in_frame.Outset(1.f / 4096); | ||
} else { | ||
// If the aspect ratio is not fixed, then this is the full destination | ||
// frame. | ||
dest_rect_in_frame = gfx::RectF(gfx::SizeF(frame_size)); | ||
} | ||
} | ||
|
||
} // namespace content |
Oops, something went wrong.