1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h"
12
13 #include <stdint.h>
14
15 #include <utility>
16
17 #include "modules/desktop_capture/desktop_geometry.h"
18 #include "modules/desktop_capture/desktop_region.h"
19 #include "rtc_base/checks.h"
20 #include "system_wrappers/include/metrics.h"
21
22 namespace webrtc {
23
BlankDetectorDesktopCapturerWrapper(std::unique_ptr<DesktopCapturer> capturer,RgbaColor blank_pixel,bool check_per_capture)24 BlankDetectorDesktopCapturerWrapper::BlankDetectorDesktopCapturerWrapper(
25 std::unique_ptr<DesktopCapturer> capturer,
26 RgbaColor blank_pixel,
27 bool check_per_capture)
28 : capturer_(std::move(capturer)),
29 blank_pixel_(blank_pixel),
30 check_per_capture_(check_per_capture) {
31 RTC_DCHECK(capturer_);
32 }
33
34 BlankDetectorDesktopCapturerWrapper::~BlankDetectorDesktopCapturerWrapper() =
35 default;
36
Start(DesktopCapturer::Callback * callback)37 void BlankDetectorDesktopCapturerWrapper::Start(
38 DesktopCapturer::Callback* callback) {
39 callback_ = callback;
40 capturer_->Start(this);
41 }
42
SetSharedMemoryFactory(std::unique_ptr<SharedMemoryFactory> shared_memory_factory)43 void BlankDetectorDesktopCapturerWrapper::SetSharedMemoryFactory(
44 std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
45 capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
46 }
47
CaptureFrame()48 void BlankDetectorDesktopCapturerWrapper::CaptureFrame() {
49 RTC_DCHECK(callback_);
50 capturer_->CaptureFrame();
51 }
52
SetExcludedWindow(WindowId window)53 void BlankDetectorDesktopCapturerWrapper::SetExcludedWindow(WindowId window) {
54 capturer_->SetExcludedWindow(window);
55 }
56
GetSourceList(SourceList * sources)57 bool BlankDetectorDesktopCapturerWrapper::GetSourceList(SourceList* sources) {
58 return capturer_->GetSourceList(sources);
59 }
60
SelectSource(SourceId id)61 bool BlankDetectorDesktopCapturerWrapper::SelectSource(SourceId id) {
62 if (check_per_capture_) {
63 // If we start capturing a new source, we must reset these members
64 // so we don't short circuit the blank detection logic.
65 is_first_frame_ = true;
66 non_blank_frame_received_ = false;
67 }
68
69 return capturer_->SelectSource(id);
70 }
71
FocusOnSelectedSource()72 bool BlankDetectorDesktopCapturerWrapper::FocusOnSelectedSource() {
73 return capturer_->FocusOnSelectedSource();
74 }
75
IsOccluded(const DesktopVector & pos)76 bool BlankDetectorDesktopCapturerWrapper::IsOccluded(const DesktopVector& pos) {
77 return capturer_->IsOccluded(pos);
78 }
79
OnCaptureResult(Result result,std::unique_ptr<DesktopFrame> frame)80 void BlankDetectorDesktopCapturerWrapper::OnCaptureResult(
81 Result result,
82 std::unique_ptr<DesktopFrame> frame) {
83 RTC_DCHECK(callback_);
84 if (result != Result::SUCCESS || non_blank_frame_received_) {
85 callback_->OnCaptureResult(result, std::move(frame));
86 return;
87 }
88
89 if (!frame) {
90 // Capturer can call the blank detector with empty frame. Blank
91 // detector regards it as a blank frame.
92 callback_->OnCaptureResult(Result::ERROR_TEMPORARY,
93 std::unique_ptr<DesktopFrame>());
94 return;
95 }
96
97 // If nothing has been changed in current frame, we do not need to check it
98 // again.
99 if (!frame->updated_region().is_empty() || is_first_frame_) {
100 last_frame_is_blank_ = IsBlankFrame(*frame);
101 is_first_frame_ = false;
102 }
103 RTC_HISTOGRAM_BOOLEAN("WebRTC.DesktopCapture.BlankFrameDetected",
104 last_frame_is_blank_);
105 if (!last_frame_is_blank_) {
106 non_blank_frame_received_ = true;
107 callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
108 return;
109 }
110
111 callback_->OnCaptureResult(Result::ERROR_TEMPORARY,
112 std::unique_ptr<DesktopFrame>());
113 }
114
IsBlankFrame(const DesktopFrame & frame) const115 bool BlankDetectorDesktopCapturerWrapper::IsBlankFrame(
116 const DesktopFrame& frame) const {
117 // We will check 7489 pixels for a frame with 1024 x 768 resolution.
118 for (int i = 0; i < frame.size().width() * frame.size().height(); i += 105) {
119 const int x = i % frame.size().width();
120 const int y = i / frame.size().width();
121 if (!IsBlankPixel(frame, x, y)) {
122 return false;
123 }
124 }
125
126 // We are verifying the pixel in the center as well.
127 return IsBlankPixel(frame, frame.size().width() / 2,
128 frame.size().height() / 2);
129 }
130
IsBlankPixel(const DesktopFrame & frame,int x,int y) const131 bool BlankDetectorDesktopCapturerWrapper::IsBlankPixel(
132 const DesktopFrame& frame,
133 int x,
134 int y) const {
135 uint8_t* pixel_data = frame.GetFrameDataAtPos(DesktopVector(x, y));
136 return RgbaColor(pixel_data) == blank_pixel_;
137 }
138
139 } // namespace webrtc
140