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:
parent
e744af5455
commit
210b8b2325
@ -185,6 +185,11 @@ class RTC_EXPORT DesktopCaptureOptions {
|
|||||||
void set_allow_wgc_capturer_fallback(bool allow) {
|
void set_allow_wgc_capturer_fallback(bool allow) {
|
||||||
allow_wgc_capturer_fallback_ = 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(RTC_ENABLE_WIN_WGC)
|
||||||
#endif // defined(WEBRTC_WIN)
|
#endif // defined(WEBRTC_WIN)
|
||||||
|
|
||||||
@ -239,6 +244,7 @@ class RTC_EXPORT DesktopCaptureOptions {
|
|||||||
#if defined(RTC_ENABLE_WIN_WGC)
|
#if defined(RTC_ENABLE_WIN_WGC)
|
||||||
bool allow_wgc_capturer_ = false;
|
bool allow_wgc_capturer_ = false;
|
||||||
bool allow_wgc_capturer_fallback_ = false;
|
bool allow_wgc_capturer_fallback_ = false;
|
||||||
|
bool allow_wgc_zero_hertz_ = false;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBRTC_USE_X11)
|
#if defined(WEBRTC_USE_X11)
|
||||||
|
|||||||
@ -192,6 +192,8 @@ HRESULT WgcCaptureSession::StartCapture(const DesktopCaptureOptions& options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allow_zero_hertz_ = options.allow_wgc_zero_hertz();
|
||||||
|
|
||||||
hr = session_->StartCapture();
|
hr = session_->StartCapture();
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
RTC_LOG(LS_ERROR) << "Failed to start CaptureSession: " << hr;
|
RTC_LOG(LS_ERROR) << "Failed to start CaptureSession: " << hr;
|
||||||
@ -234,13 +236,22 @@ bool WgcCaptureSession::GetFrame(std::unique_ptr<DesktopFrame>* output_frame) {
|
|||||||
ProcessFrame();
|
ProcessFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return false if we still don't have a valid frame leading to a
|
// Return a NULL frame and false as `result` if we still don't have a valid
|
||||||
// DesktopCapturer::Result::ERROR_PERMANENT posted by the WGC capturer.
|
// frame. This will lead to a DesktopCapturer::Result::ERROR_PERMANENT being
|
||||||
if (!queue_.current_frame()) {
|
// posted by the WGC capturer.
|
||||||
|
DesktopFrame* current_frame = queue_.current_frame();
|
||||||
|
if (!current_frame) {
|
||||||
RTC_LOG(LS_ERROR) << "GetFrame failed.";
|
RTC_LOG(LS_ERROR) << "GetFrame failed.";
|
||||||
return false;
|
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.
|
// Emit the current frame.
|
||||||
std::unique_ptr<DesktopFrame> new_frame = queue_.current_frame()->Share();
|
std::unique_ptr<DesktopFrame> new_frame = queue_.current_frame()->Share();
|
||||||
*output_frame = std::move(new_frame);
|
*output_frame = std::move(new_frame);
|
||||||
@ -294,7 +305,7 @@ HRESULT WgcCaptureSession::ProcessFrame() {
|
|||||||
|
|
||||||
queue_.MoveToNextFrame();
|
queue_.MoveToNextFrame();
|
||||||
if (queue_.current_frame() && queue_.current_frame()->IsShared()) {
|
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;
|
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
|
// 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
|
// 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
|
// 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);
|
DesktopSize image_size(image_width, image_height);
|
||||||
if (!queue_.current_frame() ||
|
if (!queue_.current_frame() ||
|
||||||
!queue_.current_frame()->size().equals(image_size)) {
|
!queue_.current_frame()->size().equals(image_size)) {
|
||||||
@ -433,6 +444,32 @@ HRESULT WgcCaptureSession::ProcessFrame() {
|
|||||||
|
|
||||||
d3d_context->Unmap(mapped_texture_.Get(), 0);
|
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)
|
if (empty_frame_credit_count_ > 0)
|
||||||
--empty_frame_credit_count_;
|
--empty_frame_credit_count_;
|
||||||
size_ = new_size;
|
size_ = new_size;
|
||||||
|
|||||||
@ -82,6 +82,8 @@ class WgcCaptureSession final {
|
|||||||
|
|
||||||
void RemoveEventHandlers();
|
void RemoveEventHandlers();
|
||||||
|
|
||||||
|
bool allow_zero_hertz() const { return allow_zero_hertz_; }
|
||||||
|
|
||||||
std::unique_ptr<EventRegistrationToken> frame_arrived_token_;
|
std::unique_ptr<EventRegistrationToken> frame_arrived_token_;
|
||||||
std::unique_ptr<EventRegistrationToken> item_closed_token_;
|
std::unique_ptr<EventRegistrationToken> item_closed_token_;
|
||||||
|
|
||||||
@ -140,6 +142,17 @@ class WgcCaptureSession final {
|
|||||||
// expected and should not be seen as an error.
|
// expected and should not be seen as an error.
|
||||||
int empty_frame_credit_count_ = 0;
|
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_;
|
SequenceChecker sequence_checker_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user