File: 0120.patch

package info (click to toggle)
firefox-esr 140.5.0esr-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,538,920 kB
  • sloc: cpp: 7,381,527; javascript: 6,388,905; ansic: 3,710,087; python: 1,393,776; xml: 628,165; asm: 426,916; java: 184,004; sh: 65,744; makefile: 19,302; objc: 13,059; perl: 12,912; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,226; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10
file content (294 lines) | stat: -rw-r--r-- 12,396 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
From: Andreas Pehrson <apehrson@mozilla.com>
Date: Thu, 12 Sep 2024 22:36:00 +0000
Subject: Bug 1918096 - In ScreenCapturerSck adapt to sources that change
 resolution. r=webrtc-reviewers,ng

If the resolution is smaller than the allocated surface, we crop.
If the resolution is larger than the allocated surface, we reconfigure with a
larger surface.

The allocated surface has the size we told it to have in the
SCStreamConfiguration, in pixels.

If the source is a screen, the size is pretty static. Changing display settings
  could affect it.
If the source is a window, the size is initially the size of the window. The
  user resizing the window affects the size.
If the source is multiple windows, the size initially seems to be that of the
  display they're sitting on. Windows across multiple displays are not captured
  into the same surface, as of macOS 14.

Differential Revision: https://phabricator.services.mozilla.com/D221941
Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/bc6215142feaab1a3f7820006129219504851bc8
---
 .../mac/desktop_frame_iosurface.h             |  9 +-
 .../mac/desktop_frame_iosurface.mm            | 47 ++++++++--
 .../mac/screen_capturer_sck.mm                | 94 +++++++++++++++++--
 3 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/modules/desktop_capture/mac/desktop_frame_iosurface.h b/modules/desktop_capture/mac/desktop_frame_iosurface.h
index 73da0f693c..ed90e40993 100644
--- a/modules/desktop_capture/mac/desktop_frame_iosurface.h
+++ b/modules/desktop_capture/mac/desktop_frame_iosurface.h
@@ -26,7 +26,7 @@ class DesktopFrameIOSurface final : public DesktopFrame {
   // Lock an IOSurfaceRef containing a snapshot of a display. Return NULL if
   // failed to lock.
   static std::unique_ptr<DesktopFrameIOSurface> Wrap(
-      rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface);
+      rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface, CGRect rect = {});
 
   ~DesktopFrameIOSurface() override;
 
@@ -35,7 +35,12 @@ class DesktopFrameIOSurface final : public DesktopFrame {
 
  private:
   // This constructor expects `io_surface` to hold a non-null IOSurfaceRef.
-  explicit DesktopFrameIOSurface(rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface);
+  DesktopFrameIOSurface(
+      rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+      uint8_t* data,
+      int32_t width,
+      int32_t height,
+      int32_t stride);
 
   const rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
 };
diff --git a/modules/desktop_capture/mac/desktop_frame_iosurface.mm b/modules/desktop_capture/mac/desktop_frame_iosurface.mm
index 11f2e9eaa2..a9b06428d1 100644
--- a/modules/desktop_capture/mac/desktop_frame_iosurface.mm
+++ b/modules/desktop_capture/mac/desktop_frame_iosurface.mm
@@ -17,7 +17,7 @@ namespace webrtc {
 
 // static
 std::unique_ptr<DesktopFrameIOSurface> DesktopFrameIOSurface::Wrap(
-    rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface) {
+    rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface, CGRect rect) {
   if (!io_surface) {
     return nullptr;
   }
@@ -42,18 +42,45 @@ std::unique_ptr<DesktopFrameIOSurface> DesktopFrameIOSurface::Wrap(
     return nullptr;
   }
 
-  return std::unique_ptr<DesktopFrameIOSurface>(
-      new DesktopFrameIOSurface(io_surface));
+  size_t surfaceWidth = IOSurfaceGetWidth(io_surface.get());
+  size_t surfaceHeight = IOSurfaceGetHeight(io_surface.get());
+  uint8_t* data =
+      static_cast<uint8_t*>(IOSurfaceGetBaseAddress(io_surface.get()));
+  size_t offset = 0;
+  size_t width = surfaceWidth;
+  size_t height = surfaceHeight;
+  size_t offsetColumns = 0;
+  size_t offsetRows = 0;
+  int32_t stride = IOSurfaceGetBytesPerRow(io_surface.get());
+  if (rect.size.width > 0 && rect.size.height > 0) {
+    width = std::floor(rect.size.width);
+    height = std::floor(rect.size.height);
+    offsetColumns = std::ceil(rect.origin.x);
+    offsetRows = std::ceil(rect.origin.y);
+    RTC_CHECK_GE(surfaceWidth, offsetColumns + width);
+    RTC_CHECK_GE(surfaceHeight, offsetRows + height);
+    offset = stride * offsetRows + bytes_per_pixel * offsetColumns;
+  }
+
+  RTC_LOG(LS_VERBOSE) << "DesktopFrameIOSurface wrapping IOSurface with size "
+                      << surfaceWidth << "x" << surfaceHeight
+                      << ". Cropping to (" << offsetColumns << "," << offsetRows
+                      << "; " << width << "x" << height
+                      << "). Stride=" << stride / bytes_per_pixel
+                      << ", buffer-offset-px=" << offset / bytes_per_pixel
+                      << ", buffer-offset-bytes=" << offset;
+
+  return std::unique_ptr<DesktopFrameIOSurface>(new DesktopFrameIOSurface(
+      io_surface, data + offset, width, height, stride));
 }
 
 DesktopFrameIOSurface::DesktopFrameIOSurface(
-    rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface)
-    : DesktopFrame(
-          DesktopSize(IOSurfaceGetWidth(io_surface.get()),
-                      IOSurfaceGetHeight(io_surface.get())),
-          IOSurfaceGetBytesPerRow(io_surface.get()),
-          static_cast<uint8_t*>(IOSurfaceGetBaseAddress(io_surface.get())),
-          nullptr),
+    rtc::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+    uint8_t* data,
+    int32_t width,
+    int32_t height,
+    int32_t stride)
+    : DesktopFrame(DesktopSize(width, height), stride, data, nullptr),
       io_surface_(io_surface) {
   RTC_DCHECK(io_surface_);
 }
diff --git a/modules/desktop_capture/mac/screen_capturer_sck.mm b/modules/desktop_capture/mac/screen_capturer_sck.mm
index 915aa90bd7..1a84a39c9c 100644
--- a/modules/desktop_capture/mac/screen_capturer_sck.mm
+++ b/modules/desktop_capture/mac/screen_capturer_sck.mm
@@ -182,6 +182,13 @@ class API_AVAILABLE(macos(14.0)) ScreenCapturerSck final
   // more accurately track the dirty rectangles from the
   // SCStreamFrameInfoDirtyRects attachment.
   bool frame_is_dirty_ RTC_GUARDED_BY(latest_frame_lock_) = true;
+
+  // Tracks whether a reconfigure is needed.
+  bool frame_needs_reconfigure_ RTC_GUARDED_BY(latest_frame_lock_) = false;
+  // If a reconfigure is needed, this will be set to the size in pixels required
+  // to fit the entire source without downscaling.
+  std::optional<CGSize> frame_reconfigure_img_size_
+      RTC_GUARDED_BY(latest_frame_lock_);
 };
 
 ScreenCapturerSck::ScreenCapturerSck(const DesktopCaptureOptions& options)
@@ -261,6 +268,7 @@ void ScreenCapturerSck::CaptureFrame() {
   }
 
   std::unique_ptr<DesktopFrame> frame;
+  bool needs_reconfigure = false;
   {
     MutexLock lock(&latest_frame_lock_);
     if (latest_frame_) {
@@ -272,6 +280,8 @@ void ScreenCapturerSck::CaptureFrame() {
         frame_is_dirty_ = false;
       }
     }
+    needs_reconfigure = frame_needs_reconfigure_;
+    frame_needs_reconfigure_ = false;
   }
 
   if (frame) {
@@ -284,6 +294,10 @@ void ScreenCapturerSck::CaptureFrame() {
                         << " CaptureFrame() -> ERROR_TEMPORARY";
     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
   }
+
+  if (needs_reconfigure) {
+    StartOrReconfigureCapturer();
+  }
 }
 
 void ScreenCapturerSck::EnsureVisible() {
@@ -308,6 +322,9 @@ void ScreenCapturerSck::EnsureVisible() {
     stream = stream_;
     stream_ = nil;
     filter_ = nil;
+    MutexLock lock2(&latest_frame_lock_);
+    frame_needs_reconfigure_ = false;
+    frame_reconfigure_img_size_ = std::nullopt;
   }
   [stream removeStreamOutput:helper_ type:SCStreamOutputTypeScreen error:nil];
   [stream stopCaptureWithCompletionHandler:nil];
@@ -474,13 +491,22 @@ void ScreenCapturerSck::StartWithFilter(SCContentFilter* __strong filter) {
   {
     MutexLock lock(&latest_frame_lock_);
     latest_frame_dpi_ = filter.pointPixelScale * kStandardDPI;
+    if (filter_ != filter) {
+      frame_reconfigure_img_size_ = std::nullopt;
+    }
+    auto sourceImgRect = frame_reconfigure_img_size_.value_or(
+        CGSizeMake(filter.contentRect.size.width * filter.pointPixelScale,
+                   filter.contentRect.size.height * filter.pointPixelScale));
+    config.width = sourceImgRect.width;
+    config.height = sourceImgRect.height;
   }
 
   filter_ = filter;
 
   if (stream_) {
     RTC_LOG(LS_INFO) << "ScreenCapturerSck " << this
-                     << " Updating stream configuration.";
+                     << " Updating stream configuration to size="
+                     << config.width << "x" << config.height << ".";
     [stream_ updateContentFilter:filter completionHandler:nil];
     [stream_ updateConfiguration:config completionHandler:nil];
   } else {
@@ -525,21 +551,69 @@ void ScreenCapturerSck::StartWithFilter(SCContentFilter* __strong filter) {
 
 void ScreenCapturerSck::OnNewIOSurface(IOSurfaceRef io_surface,
                                        NSDictionary* attachment) {
-  RTC_LOG(LS_VERBOSE) << "ScreenCapturerSck " << this << " " << __func__
-                      << " width=" << IOSurfaceGetWidth(io_surface)
-                      << ", height=" << IOSurfaceGetHeight(io_surface) << ".";
-
+  double scaleFactor = 1;
+  double contentScale = 1;
+  CGRect contentRect = {};
+  CGRect boundingRect = {};
+  CGRect overlayRect = {};
   const auto* dirty_rects = (NSArray*)attachment[SCStreamFrameInfoDirtyRects];
+  if (auto factor = (NSNumber*)attachment[SCStreamFrameInfoScaleFactor]) {
+    scaleFactor = [factor floatValue];
+  }
+  if (auto scale = (NSNumber*)attachment[SCStreamFrameInfoContentScale]) {
+    contentScale = [scale floatValue];
+  }
+  if (const auto* rectDict =
+          (__bridge CFDictionaryRef)attachment[SCStreamFrameInfoContentRect]) {
+    if (!CGRectMakeWithDictionaryRepresentation(rectDict, &contentRect)) {
+      contentRect = CGRect();
+    }
+  }
+  if (const auto* rectDict =
+          (__bridge CFDictionaryRef)attachment[SCStreamFrameInfoBoundingRect]) {
+    if (!CGRectMakeWithDictionaryRepresentation(rectDict, &boundingRect)) {
+      boundingRect = CGRect();
+    }
+  }
+  if (@available(macOS 14.2, *)) {
+    if (const auto* rectDict = (__bridge CFDictionaryRef)
+            attachment[SCStreamFrameInfoPresenterOverlayContentRect]) {
+      if (!CGRectMakeWithDictionaryRepresentation(rectDict, &overlayRect)) {
+        overlayRect = CGRect();
+      }
+    }
+  }
+
+  auto imgBoundingRect = CGRectMake(scaleFactor * boundingRect.origin.x,
+                                    scaleFactor * boundingRect.origin.y,
+                                    scaleFactor * boundingRect.size.width,
+                                    scaleFactor * boundingRect.size.height);
 
   rtc::ScopedCFTypeRef<IOSurfaceRef> scoped_io_surface(
       io_surface, rtc::RetainPolicy::RETAIN);
   std::unique_ptr<DesktopFrameIOSurface> desktop_frame_io_surface =
-      DesktopFrameIOSurface::Wrap(scoped_io_surface);
+      DesktopFrameIOSurface::Wrap(scoped_io_surface, imgBoundingRect);
   if (!desktop_frame_io_surface) {
     RTC_LOG(LS_ERROR) << "Failed to lock IOSurface.";
     return;
   }
 
+  const size_t width = IOSurfaceGetWidth(io_surface);
+  const size_t height = IOSurfaceGetHeight(io_surface);
+
+  RTC_LOG(LS_VERBOSE) << "ScreenCapturerSck " << this << " " << __func__
+                      << ". New surface: width=" << width
+                      << ", height=" << height << ", contentRect="
+                      << NSStringFromRect(contentRect).UTF8String
+                      << ", boundingRect="
+                      << NSStringFromRect(boundingRect).UTF8String
+                      << ", overlayRect=("
+                      << NSStringFromRect(overlayRect).UTF8String
+                      << ", scaleFactor=" << scaleFactor
+                      << ", contentScale=" << contentScale
+                      << ". Cropping to rect "
+                      << NSStringFromRect(imgBoundingRect).UTF8String << ".";
+
   std::unique_ptr<SharedDesktopFrame> frame =
       SharedDesktopFrame::Wrap(std::move(desktop_frame_io_surface));
 
@@ -575,8 +649,14 @@ void ScreenCapturerSck::OnNewIOSurface(IOSurfaceRef io_surface,
     }
   }
 
+  MutexLock lock(&latest_frame_lock_);
+  if (contentScale > 0 && contentScale < 1) {
+    frame_needs_reconfigure_ = true;
+    double scale = 1 / contentScale;
+    frame_reconfigure_img_size_ =
+        CGSizeMake(std::ceil(scale * width), std::ceil(scale * height));
+  }
   if (dirty) {
-    MutexLock lock(&latest_frame_lock_);
     frame_is_dirty_ = true;
     std::swap(latest_frame_, frame);
   }