-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BlankDetectorDesktopCapturerWrapper to detect a blank DesktopFrame
DXGI capturer highly depends on video adapter and its driver, as well as Windows itself. I recently found it cannot work on my virtualbox instance any more, which indicates it may not work well on some specific systems. What worse is, the APIs do not return a failure in such case. So this change adds a BlankDetectorDesktopCapturerWrapper, which samples several pixels in the frame returned by a DesktopCapturer implementation. If all the pixels selected are blank, this wrapper returns a failure. A typical usage is to combine BlankDetectorDesktopCapturerWrapper with FallbackDesktopCapturerWrapper, and use GDI capturer in case of failure. Usually less than 10000 pixels are checked, so the BlankDetectorDesktopCapturerWrapper should not significant impact the capturer performance. This change is expected to resolve bug 682112 in another dimension. BUG=chromium:682112 Review-Url: https://codereview.webrtc.org/2709523003 Cr-Original-Commit-Position: refs/heads/master@{#16984} Committed: https://chromium.googlesource.com/external/webrtc/+/c4e9d210b3516c7b2faa32f24409a2e626599255 Review-Url: https://codereview.webrtc.org/2709523003 Cr-Commit-Position: refs/heads/master@{#17024} (cherry picked from commit ccf57a7) Review-Url: https://codereview.webrtc.org/2748813002 . Cr-Commit-Position: refs/branch-heads/58@{#2} Cr-Branched-From: f31969a-refs/heads/master@{#16937}
- Loading branch information
1 parent
c279861
commit c622c51
Showing
6 changed files
with
378 additions
and
30 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
115 changes: 115 additions & 0 deletions
115
webrtc/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.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,115 @@ | ||
/* | ||
* Copyright (c) 2017 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 "webrtc/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h" | ||
|
||
#include <algorithm> | ||
#include <utility> | ||
|
||
#include "webrtc/base/checks.h" | ||
#include "webrtc/modules/desktop_capture/desktop_geometry.h" | ||
|
||
namespace webrtc { | ||
|
||
BlankDetectorDesktopCapturerWrapper::BlankDetectorDesktopCapturerWrapper( | ||
std::unique_ptr<DesktopCapturer> capturer, | ||
RgbaColor blank_pixel) | ||
: capturer_(std::move(capturer)), | ||
blank_pixel_(blank_pixel) { | ||
RTC_DCHECK(capturer_); | ||
} | ||
|
||
BlankDetectorDesktopCapturerWrapper::~BlankDetectorDesktopCapturerWrapper() = | ||
default; | ||
|
||
void BlankDetectorDesktopCapturerWrapper::Start( | ||
DesktopCapturer::Callback* callback) { | ||
capturer_->Start(this); | ||
callback_ = callback; | ||
} | ||
|
||
void BlankDetectorDesktopCapturerWrapper::SetSharedMemoryFactory( | ||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) { | ||
capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory)); | ||
} | ||
|
||
void BlankDetectorDesktopCapturerWrapper::CaptureFrame() { | ||
RTC_DCHECK(callback_); | ||
capturer_->CaptureFrame(); | ||
} | ||
|
||
void BlankDetectorDesktopCapturerWrapper::SetExcludedWindow(WindowId window) { | ||
capturer_->SetExcludedWindow(window); | ||
} | ||
|
||
bool BlankDetectorDesktopCapturerWrapper::GetSourceList(SourceList* sources) { | ||
return capturer_->GetSourceList(sources); | ||
} | ||
|
||
bool BlankDetectorDesktopCapturerWrapper::SelectSource(SourceId id) { | ||
return capturer_->SelectSource(id); | ||
} | ||
|
||
bool BlankDetectorDesktopCapturerWrapper::FocusOnSelectedSource() { | ||
return capturer_->FocusOnSelectedSource(); | ||
} | ||
|
||
void BlankDetectorDesktopCapturerWrapper::OnCaptureResult( | ||
Result result, | ||
std::unique_ptr<DesktopFrame> frame) { | ||
RTC_DCHECK(callback_); | ||
if (result != Result::SUCCESS || non_blank_frame_received_) { | ||
callback_->OnCaptureResult(result, std::move(frame)); | ||
return; | ||
} | ||
|
||
RTC_DCHECK(frame); | ||
|
||
// If nothing has been changed in current frame, we do not need to check it | ||
// again. | ||
if (!frame->updated_region().is_empty() || is_first_frame_) { | ||
last_frame_is_blank_ = IsBlankFrame(*frame); | ||
is_first_frame_ = false; | ||
} | ||
if (!last_frame_is_blank_) { | ||
non_blank_frame_received_ = true; | ||
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame)); | ||
return; | ||
} | ||
|
||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, | ||
std::unique_ptr<DesktopFrame>()); | ||
} | ||
|
||
bool BlankDetectorDesktopCapturerWrapper::IsBlankFrame( | ||
const DesktopFrame& frame) const { | ||
// We will check 7489 pixels for a frame with 1024 x 768 resolution. | ||
for (int i = 0; i < frame.size().width() * frame.size().height(); i += 105) { | ||
const int x = i % frame.size().width(); | ||
const int y = i / frame.size().width(); | ||
if (!IsBlankPixel(frame, x, y)) { | ||
return false; | ||
} | ||
} | ||
|
||
// We are verifying the pixel in the center as well. | ||
return IsBlankPixel(frame, frame.size().width() / 2, | ||
frame.size().height() / 2); | ||
} | ||
|
||
bool BlankDetectorDesktopCapturerWrapper::IsBlankPixel( | ||
const DesktopFrame& frame, | ||
int x, | ||
int y) const { | ||
uint8_t* pixel_data = frame.GetFrameDataAtPos(DesktopVector(x, y)); | ||
return RgbaColor(pixel_data) == blank_pixel_; | ||
} | ||
|
||
} // namespace webrtc |
74 changes: 74 additions & 0 deletions
74
webrtc/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h
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,74 @@ | ||
/* | ||
* Copyright (c) 2017 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. | ||
*/ | ||
|
||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_BLANK_DETECTOR_DESKTOP_CAPTURER_WRAPPER_H_ | ||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_BLANK_DETECTOR_DESKTOP_CAPTURER_WRAPPER_H_ | ||
|
||
#include <memory> | ||
|
||
#include "webrtc/modules/desktop_capture/desktop_capturer.h" | ||
#include "webrtc/modules/desktop_capture/rgba_color.h" | ||
|
||
namespace webrtc { | ||
|
||
// A DesktopCapturer wrapper detects the return value of its owned | ||
// DesktopCapturer implementation. If sampled pixels returned by the | ||
// DesktopCapturer implementation all equal to the blank pixel, this wrapper | ||
// returns ERROR_TEMPORARY. If the DesktopCapturer implementation fails for too | ||
// many times, this wrapper returns ERROR_PERMANENT. | ||
class BlankDetectorDesktopCapturerWrapper final | ||
: public DesktopCapturer, | ||
public DesktopCapturer::Callback { | ||
public: | ||
// Creates BlankDetectorDesktopCapturerWrapper. BlankDesktopCapturerWrapper | ||
// takes ownership of |capturer|. The |blank_pixel| is the unmodified color | ||
// returned by the |capturer|. | ||
BlankDetectorDesktopCapturerWrapper(std::unique_ptr<DesktopCapturer> capturer, | ||
RgbaColor blank_pixel); | ||
~BlankDetectorDesktopCapturerWrapper() override; | ||
|
||
// DesktopCapturer interface. | ||
void Start(DesktopCapturer::Callback* callback) override; | ||
void SetSharedMemoryFactory( | ||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) override; | ||
void CaptureFrame() override; | ||
void SetExcludedWindow(WindowId window) override; | ||
bool GetSourceList(SourceList* sources) override; | ||
bool SelectSource(SourceId id) override; | ||
bool FocusOnSelectedSource() override; | ||
|
||
private: | ||
// DesktopCapturer::Callback interface. | ||
void OnCaptureResult(Result result, | ||
std::unique_ptr<DesktopFrame> frame) override; | ||
|
||
bool IsBlankFrame(const DesktopFrame& frame) const; | ||
|
||
// Detects whether pixel at (x, y) equals to |blank_pixel_|. | ||
bool IsBlankPixel(const DesktopFrame& frame, int x, int y) const; | ||
|
||
const std::unique_ptr<DesktopCapturer> capturer_; | ||
const RgbaColor blank_pixel_; | ||
|
||
// Whether a non-blank frame has been received. | ||
bool non_blank_frame_received_ = false; | ||
|
||
// Whether the last frame is blank. | ||
bool last_frame_is_blank_ = false; | ||
|
||
// Whether current frame is the first frame. | ||
bool is_first_frame_ = true; | ||
|
||
DesktopCapturer::Callback* callback_ = nullptr; | ||
}; | ||
|
||
} // namespace webrtc | ||
|
||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_BLANK_DETECTOR_DESKTOP_CAPTURER_WRAPPER_H_ |
Oops, something went wrong.