xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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