Adds 0Hz support to WGC behind a flag

Also requires changes in Chrome, see https://chromium-review.googlesource.com/c/chromium/src/+/4315678

NOTRY=True
NOPRESUBMIT=True

Bug: chromium:1421242
Change-Id: Id1e6675e4ab4d1d82b011b85b799dc4e5b757c12
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/296501
Commit-Queue: Henrik Andreassson <henrika@webrtc.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#39542}
This commit is contained in:
henrika 2023-03-13 11:44:16 +01:00 committed by WebRTC LUCI CQ
parent e744af5455
commit 210b8b2325
3 changed files with 61 additions and 5 deletions

View File

@ -185,6 +185,11 @@ class RTC_EXPORT DesktopCaptureOptions {
void set_allow_wgc_capturer_fallback(bool allow) {
allow_wgc_capturer_fallback_ = allow;
}
// This flag enables 0Hz mode in combination with the WGC capturer.
// The flag has no effect if the allow_wgc_capturer flag is false.
bool allow_wgc_zero_hertz() const { return allow_wgc_zero_hertz_; }
void set_allow_wgc_zero_hertz(bool allow) { allow_wgc_zero_hertz_ = allow; }
#endif // defined(RTC_ENABLE_WIN_WGC)
#endif // defined(WEBRTC_WIN)
@ -239,6 +244,7 @@ class RTC_EXPORT DesktopCaptureOptions {
#if defined(RTC_ENABLE_WIN_WGC)
bool allow_wgc_capturer_ = false;
bool allow_wgc_capturer_fallback_ = false;
bool allow_wgc_zero_hertz_ = false;
#endif
#endif
#if defined(WEBRTC_USE_X11)

View File

@ -192,6 +192,8 @@ HRESULT WgcCaptureSession::StartCapture(const DesktopCaptureOptions& options) {
}
}
allow_zero_hertz_ = options.allow_wgc_zero_hertz();
hr = session_->StartCapture();
if (FAILED(hr)) {
RTC_LOG(LS_ERROR) << "Failed to start CaptureSession: " << hr;
@ -234,13 +236,22 @@ bool WgcCaptureSession::GetFrame(std::unique_ptr<DesktopFrame>* output_frame) {
ProcessFrame();
}
// Return false if we still don't have a valid frame leading to a
// DesktopCapturer::Result::ERROR_PERMANENT posted by the WGC capturer.
if (!queue_.current_frame()) {
// Return a NULL frame and false as `result` if we still don't have a valid
// frame. This will lead to a DesktopCapturer::Result::ERROR_PERMANENT being
// posted by the WGC capturer.
DesktopFrame* current_frame = queue_.current_frame();
if (!current_frame) {
RTC_LOG(LS_ERROR) << "GetFrame failed.";
return false;
}
// Swap in the DesktopRegion in `damage_region_` which is updated in
// ProcessFrame(). The updated region is either empty or the full rect being
// captured where an empty damage region corresponds to "no change in content
// since last frame".
current_frame->mutable_updated_region()->Swap(&damage_region_);
damage_region_.Clear();
// Emit the current frame.
std::unique_ptr<DesktopFrame> new_frame = queue_.current_frame()->Share();
*output_frame = std::move(new_frame);
@ -294,7 +305,7 @@ HRESULT WgcCaptureSession::ProcessFrame() {
queue_.MoveToNextFrame();
if (queue_.current_frame() && queue_.current_frame()->IsShared()) {
RTC_DLOG(LS_WARNING) << "Overwriting frame that is still shared.";
RTC_DLOG(LS_VERBOSE) << "Overwriting frame that is still shared.";
}
ComPtr<WGC::IDirect3D11CaptureFrame> capture_frame;
@ -410,7 +421,7 @@ HRESULT WgcCaptureSession::ProcessFrame() {
// Allocate the current frame buffer only if it is not already allocated or
// if the size has changed. Note that we can't reallocate other buffers at
// this point, since the caller may still be reading from them. The queue can
// hold up tp two frames.
// hold up to two frames.
DesktopSize image_size(image_width, image_height);
if (!queue_.current_frame() ||
!queue_.current_frame()->size().equals(image_size)) {
@ -433,6 +444,32 @@ HRESULT WgcCaptureSession::ProcessFrame() {
d3d_context->Unmap(mapped_texture_.Get(), 0);
if (allow_zero_hertz()) {
DesktopFrame* previous_frame = queue_.previous_frame();
if (previous_frame) {
const int previous_frame_size =
previous_frame->stride() * previous_frame->size().height();
const int current_frame_size =
current_frame->stride() * current_frame->size().height();
// Compare the latest frame with the previous and check if the frames are
// equal (both contain the exact same pixel values).
if (current_frame_size == previous_frame_size) {
const bool frames_are_equal = !memcmp(
current_frame->data(), previous_frame->data(), current_frame_size);
if (!frames_are_equal) {
// TODO(https://crbug.com/1421242): If we had an API to report proper
// damage regions we should be doing AddRect() with a SetRect() call
// on a resize.
damage_region_.SetRect(DesktopRect::MakeSize(current_frame->size()));
}
} else {
// Mark resized frames as damaged.
damage_region_.SetRect(DesktopRect::MakeSize(current_frame->size()));
}
}
}
if (empty_frame_credit_count_ > 0)
--empty_frame_credit_count_;
size_ = new_size;

View File

@ -82,6 +82,8 @@ class WgcCaptureSession final {
void RemoveEventHandlers();
bool allow_zero_hertz() const { return allow_zero_hertz_; }
std::unique_ptr<EventRegistrationToken> frame_arrived_token_;
std::unique_ptr<EventRegistrationToken> item_closed_token_;
@ -140,6 +142,17 @@ class WgcCaptureSession final {
// expected and should not be seen as an error.
int empty_frame_credit_count_ = 0;
// Caches the value of DesktopCaptureOptions.allow_wgc_zero_hertz() in
// StartCapture(). Adds 0Hz detection in ProcessFrame() when enabled which
// adds complexity since memcmp() is performed on two successive frames.
bool allow_zero_hertz_ = false;
// Tracks damage region updates that were reported since the last time a frame
// was captured. Currently only supports either the complete rect being
// captured or an empty region. Will always be empty if `allow_zero_hertz_` is
// false.
DesktopRegion damage_region_;
SequenceChecker sequence_checker_;
};