Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: media/video/capture/screen/screen_capturer_mac.mm

Issue 12047101: Move screen capturers from remoting/capturer to media/video/capturer/screen (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/capturer/video_frame_capturer.h" 5 #include "media/video/capture/screen/screen_capturer.h"
6 6
7 #include <ApplicationServices/ApplicationServices.h> 7 #include <ApplicationServices/ApplicationServices.h>
8 #include <Cocoa/Cocoa.h> 8 #include <Cocoa/Cocoa.h>
9 #include <dlfcn.h> 9 #include <dlfcn.h>
10 #include <IOKit/pwr_mgt/IOPMLib.h> 10 #include <IOKit/pwr_mgt/IOPMLib.h>
11 #include <OpenGL/CGLMacro.h> 11 #include <OpenGL/CGLMacro.h>
12 #include <OpenGL/OpenGL.h> 12 #include <OpenGL/OpenGL.h>
13 #include <set> 13 #include <set>
14 #include <stddef.h> 14 #include <stddef.h>
15 15
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/file_path.h" 17 #include "base/file_path.h"
18 #include "base/mac/mac_util.h" 18 #include "base/mac/mac_util.h"
19 #include "base/mac/scoped_cftyperef.h" 19 #include "base/mac/scoped_cftyperef.h"
20 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
21 #include "base/scoped_native_library.h" 21 #include "base/scoped_native_library.h"
22 #include "base/synchronization/waitable_event.h" 22 #include "base/synchronization/waitable_event.h"
23 #include "base/time.h" 23 #include "base/time.h"
24 #include "remoting/capturer/capture_data.h" 24 #include "media/video/capture/screen/mac/scoped_pixel_buffer_object.h"
25 #include "remoting/capturer/mac/scoped_pixel_buffer_object.h" 25 #include "media/video/capture/screen/mouse_cursor_shape.h"
26 #include "remoting/capturer/mouse_cursor_shape.h" 26 #include "media/video/capture/screen/screen_capture_data.h"
27 #include "remoting/capturer/video_frame.h" 27 #include "media/video/capture/screen/screen_capture_frame.h"
28 #include "remoting/capturer/video_frame_capturer_helper.h" 28 #include "media/video/capture/screen/screen_capture_frame_queue.h"
29 #include "remoting/capturer/video_frame_queue.h" 29 #include "media/video/capture/screen/screen_capturer_helper.h"
30 30
31 namespace remoting { 31 namespace media {
32 32
33 namespace { 33 namespace {
34 34
35 // Definitions used to dynamic-link to deprecated OS 10.6 functions. 35 // Definitions used to dynamic-link to deprecated OS 10.6 functions.
36 const char* kApplicationServicesLibraryName = 36 const char* kApplicationServicesLibraryName =
37 "/System/Library/Frameworks/ApplicationServices.framework/" 37 "/System/Library/Frameworks/ApplicationServices.framework/"
38 "ApplicationServices"; 38 "ApplicationServices";
39 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); 39 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID);
40 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); 40 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID);
41 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); 41 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 memcpy(dest_plane, src_plane, bytes_per_line); 75 memcpy(dest_plane, src_plane, bytes_per_line);
76 src_plane += src_plane_stride; 76 src_plane += src_plane_stride;
77 dest_plane += dest_plane_stride; 77 dest_plane += dest_plane_stride;
78 } 78 }
79 } 79 }
80 80
81 // The amount of time allowed for displays to reconfigure. 81 // The amount of time allowed for displays to reconfigure.
82 const int64 kDisplayConfigurationEventTimeoutInSeconds = 10; 82 const int64 kDisplayConfigurationEventTimeoutInSeconds = 10;
83 83
84 // A class representing a full-frame pixel buffer. 84 // A class representing a full-frame pixel buffer.
85 class VideoFrameMac : public VideoFrame { 85 class ScreenCaptureFrameMac : public ScreenCaptureFrame {
86 public: 86 public:
87 explicit VideoFrameMac(const SkISize& size); 87 explicit ScreenCaptureFrameMac(const SkISize& size);
88 virtual ~VideoFrameMac(); 88 virtual ~ScreenCaptureFrameMac();
89 89
90 const SkIPoint& dpi() const { return dpi_; } 90 const SkIPoint& dpi() const { return dpi_; }
91 91
92 private: 92 private:
93 // Allocated pixel buffer. 93 // Allocated pixel buffer.
94 scoped_array<uint8> data_; 94 scoped_array<uint8> data_;
95 95
96 // DPI settings for this buffer. 96 // DPI settings for this buffer.
97 SkIPoint dpi_; 97 SkIPoint dpi_;
98 98
99 DISALLOW_COPY_AND_ASSIGN(VideoFrameMac); 99 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureFrameMac);
100 }; 100 };
101 101
102 // A class to perform video frame capturing for mac. 102 // A class to perform video frame capturing for mac.
103 class VideoFrameCapturerMac : public VideoFrameCapturer { 103 class ScreenCapturerMac : public ScreenCapturer {
104 public: 104 public:
105 VideoFrameCapturerMac(); 105 ScreenCapturerMac();
106 virtual ~VideoFrameCapturerMac(); 106 virtual ~ScreenCapturerMac();
107 107
108 bool Init(); 108 bool Init();
109 109
110 // Overridden from VideoFrameCapturer: 110 // Overridden from ScreenCapturer:
111 virtual void Start(Delegate* delegate) OVERRIDE; 111 virtual void Start(Delegate* delegate) OVERRIDE;
112 virtual void Stop() OVERRIDE; 112 virtual void Stop() OVERRIDE;
113 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; 113 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE;
114 virtual void CaptureFrame() OVERRIDE; 114 virtual void CaptureFrame() OVERRIDE;
115 115
116 private: 116 private:
117 void CaptureCursor(); 117 void CaptureCursor();
118 118
119 void GlBlitFast(const VideoFrame& buffer, const SkRegion& region); 119 void GlBlitFast(const ScreenCaptureFrame& buffer, const SkRegion& region);
120 void GlBlitSlow(const VideoFrame& buffer); 120 void GlBlitSlow(const ScreenCaptureFrame& buffer);
121 void CgBlitPreLion(const VideoFrame& buffer, const SkRegion& region); 121 void CgBlitPreLion(const ScreenCaptureFrame& buffer, const SkRegion& region);
122 void CgBlitPostLion(const VideoFrame& buffer, const SkRegion& region); 122 void CgBlitPostLion(const ScreenCaptureFrame& buffer, const SkRegion& region);
123 123
124 // Called when the screen configuration is changed. 124 // Called when the screen configuration is changed.
125 void ScreenConfigurationChanged(); 125 void ScreenConfigurationChanged();
126 126
127 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); 127 void ScreenRefresh(CGRectCount count, const CGRect *rect_array);
128 void ScreenUpdateMove(CGScreenUpdateMoveDelta delta, 128 void ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
129 size_t count, 129 size_t count,
130 const CGRect *rect_array); 130 const CGRect *rect_array);
131 void DisplaysReconfigured(CGDirectDisplayID display, 131 void DisplaysReconfigured(CGDirectDisplayID display,
132 CGDisplayChangeSummaryFlags flags); 132 CGDisplayChangeSummaryFlags flags);
133 static void ScreenRefreshCallback(CGRectCount count, 133 static void ScreenRefreshCallback(CGRectCount count,
134 const CGRect *rect_array, 134 const CGRect *rect_array,
135 void *user_parameter); 135 void *user_parameter);
136 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, 136 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta,
137 size_t count, 137 size_t count,
138 const CGRect *rect_array, 138 const CGRect *rect_array,
139 void *user_parameter); 139 void *user_parameter);
140 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, 140 static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
141 CGDisplayChangeSummaryFlags flags, 141 CGDisplayChangeSummaryFlags flags,
142 void *user_parameter); 142 void *user_parameter);
143 143
144 void ReleaseBuffers(); 144 void ReleaseBuffers();
145 145
146 Delegate* delegate_; 146 Delegate* delegate_;
147 147
148 CGLContextObj cgl_context_; 148 CGLContextObj cgl_context_;
149 ScopedPixelBufferObject pixel_buffer_object_; 149 ScopedPixelBufferObject pixel_buffer_object_;
150 150
151 // Queue of the frames buffers. 151 // Queue of the frames buffers.
152 VideoFrameQueue queue_; 152 ScreenCaptureFrameQueue queue_;
153 153
154 // Current display configuration. 154 // Current display configuration.
155 std::vector<CGDirectDisplayID> display_ids_; 155 std::vector<CGDirectDisplayID> display_ids_;
156 SkIRect desktop_bounds_; 156 SkIRect desktop_bounds_;
157 157
158 // A thread-safe list of invalid rectangles, and the size of the most 158 // A thread-safe list of invalid rectangles, and the size of the most
159 // recently captured screen. 159 // recently captured screen.
160 VideoFrameCapturerHelper helper_; 160 ScreenCapturerHelper helper_;
161 161
162 // Image of the last cursor that we sent to the client. 162 // Image of the last cursor that we sent to the client.
163 base::mac::ScopedCFTypeRef<CGImageRef> current_cursor_; 163 base::mac::ScopedCFTypeRef<CGImageRef> current_cursor_;
164 164
165 // Contains an invalid region from the previous capture. 165 // Contains an invalid region from the previous capture.
166 SkRegion last_invalid_region_; 166 SkRegion last_invalid_region_;
167 167
168 // Used to ensure that frame captures do not take place while displays 168 // Used to ensure that frame captures do not take place while displays
169 // are being reconfigured. 169 // are being reconfigured.
170 base::WaitableEvent display_configuration_capture_event_; 170 base::WaitableEvent display_configuration_capture_event_;
171 171
172 // Records the Ids of attached displays which are being reconfigured. 172 // Records the Ids of attached displays which are being reconfigured.
173 // Accessed on the thread on which we are notified of display events. 173 // Accessed on the thread on which we are notified of display events.
174 std::set<CGDirectDisplayID> reconfiguring_displays_; 174 std::set<CGDirectDisplayID> reconfiguring_displays_;
175 175
176 // Power management assertion to prevent the screen from sleeping. 176 // Power management assertion to prevent the screen from sleeping.
177 IOPMAssertionID power_assertion_id_display_; 177 IOPMAssertionID power_assertion_id_display_;
178 178
179 // Power management assertion to indicate that the user is active. 179 // Power management assertion to indicate that the user is active.
180 IOPMAssertionID power_assertion_id_user_; 180 IOPMAssertionID power_assertion_id_user_;
181 181
182 // Dynamically link to deprecated APIs for Mac OS X 10.6 support. 182 // Dynamically link to deprecated APIs for Mac OS X 10.6 support.
183 base::ScopedNativeLibrary app_services_library_; 183 base::ScopedNativeLibrary app_services_library_;
184 CGDisplayBaseAddressFunc cg_display_base_address_; 184 CGDisplayBaseAddressFunc cg_display_base_address_;
185 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_; 185 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_;
186 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_; 186 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_;
187 base::ScopedNativeLibrary opengl_library_; 187 base::ScopedNativeLibrary opengl_library_;
188 CGLSetFullScreenFunc cgl_set_full_screen_; 188 CGLSetFullScreenFunc cgl_set_full_screen_;
189 189
190 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); 190 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
191 }; 191 };
192 192
193 VideoFrameMac::VideoFrameMac(const SkISize& size) { 193 ScreenCaptureFrameMac::ScreenCaptureFrameMac(const SkISize& size) {
194 set_bytes_per_row(size.width() * sizeof(uint32_t)); 194 set_bytes_per_row(size.width() * sizeof(uint32_t));
195 set_dimensions(size); 195 set_dimensions(size);
196 196
197 size_t buffer_size = size.width() * size.height() * sizeof(uint32_t); 197 size_t buffer_size = size.width() * size.height() * sizeof(uint32_t);
198 data_.reset(new uint8[buffer_size]); 198 data_.reset(new uint8[buffer_size]);
199 set_pixels(data_.get()); 199 set_pixels(data_.get());
200 200
201 // TODO(wez): Move the ugly DPI code into a helper. 201 // TODO(wez): Move the ugly DPI code into a helper.
202 NSScreen* screen = [NSScreen mainScreen]; 202 NSScreen* screen = [NSScreen mainScreen];
203 NSDictionary* attr = [screen deviceDescription]; 203 NSDictionary* attr = [screen deviceDescription];
204 NSSize resolution = [[attr objectForKey: NSDeviceResolution] sizeValue]; 204 NSSize resolution = [[attr objectForKey: NSDeviceResolution] sizeValue];
205 dpi_.set(resolution.width, resolution.height); 205 dpi_.set(resolution.width, resolution.height);
206 } 206 }
207 207
208 VideoFrameMac::~VideoFrameMac() { 208 ScreenCaptureFrameMac::~ScreenCaptureFrameMac() {
209 } 209 }
210 210
211 VideoFrameCapturerMac::VideoFrameCapturerMac() 211 ScreenCapturerMac::ScreenCapturerMac()
212 : delegate_(NULL), 212 : delegate_(NULL),
213 cgl_context_(NULL), 213 cgl_context_(NULL),
214 display_configuration_capture_event_(false, true), 214 display_configuration_capture_event_(false, true),
215 power_assertion_id_display_(kIOPMNullAssertionID), 215 power_assertion_id_display_(kIOPMNullAssertionID),
216 power_assertion_id_user_(kIOPMNullAssertionID), 216 power_assertion_id_user_(kIOPMNullAssertionID),
217 cg_display_base_address_(NULL), 217 cg_display_base_address_(NULL),
218 cg_display_bytes_per_row_(NULL), 218 cg_display_bytes_per_row_(NULL),
219 cg_display_bits_per_pixel_(NULL), 219 cg_display_bits_per_pixel_(NULL),
220 cgl_set_full_screen_(NULL) 220 cgl_set_full_screen_(NULL)
221 { 221 {
222 } 222 }
223 223
224 VideoFrameCapturerMac::~VideoFrameCapturerMac() { 224 ScreenCapturerMac::~ScreenCapturerMac() {
225 ReleaseBuffers(); 225 ReleaseBuffers();
226 CGUnregisterScreenRefreshCallback( 226 CGUnregisterScreenRefreshCallback(
227 VideoFrameCapturerMac::ScreenRefreshCallback, this); 227 ScreenCapturerMac::ScreenRefreshCallback, this);
228 CGScreenUnregisterMoveCallback( 228 CGScreenUnregisterMoveCallback(
229 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); 229 ScreenCapturerMac::ScreenUpdateMoveCallback, this);
230 CGError err = CGDisplayRemoveReconfigurationCallback( 230 CGError err = CGDisplayRemoveReconfigurationCallback(
231 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); 231 ScreenCapturerMac::DisplaysReconfiguredCallback, this);
232 if (err != kCGErrorSuccess) { 232 if (err != kCGErrorSuccess) {
233 LOG(ERROR) << "CGDisplayRemoveReconfigurationCallback " << err; 233 LOG(ERROR) << "CGDisplayRemoveReconfigurationCallback " << err;
234 } 234 }
235 } 235 }
236 236
237 bool VideoFrameCapturerMac::Init() { 237 bool ScreenCapturerMac::Init() {
238 CGError err = CGRegisterScreenRefreshCallback( 238 CGError err = CGRegisterScreenRefreshCallback(
239 VideoFrameCapturerMac::ScreenRefreshCallback, this); 239 ScreenCapturerMac::ScreenRefreshCallback, this);
240 if (err != kCGErrorSuccess) { 240 if (err != kCGErrorSuccess) {
241 LOG(ERROR) << "CGRegisterScreenRefreshCallback " << err; 241 LOG(ERROR) << "CGRegisterScreenRefreshCallback " << err;
242 return false; 242 return false;
243 } 243 }
244 244
245 err = CGScreenRegisterMoveCallback( 245 err = CGScreenRegisterMoveCallback(
246 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); 246 ScreenCapturerMac::ScreenUpdateMoveCallback, this);
247 if (err != kCGErrorSuccess) { 247 if (err != kCGErrorSuccess) {
248 LOG(ERROR) << "CGScreenRegisterMoveCallback " << err; 248 LOG(ERROR) << "CGScreenRegisterMoveCallback " << err;
249 return false; 249 return false;
250 } 250 }
251 err = CGDisplayRegisterReconfigurationCallback( 251 err = CGDisplayRegisterReconfigurationCallback(
252 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); 252 ScreenCapturerMac::DisplaysReconfiguredCallback, this);
253 if (err != kCGErrorSuccess) { 253 if (err != kCGErrorSuccess) {
254 LOG(ERROR) << "CGDisplayRegisterReconfigurationCallback " << err; 254 LOG(ERROR) << "CGDisplayRegisterReconfigurationCallback " << err;
255 return false; 255 return false;
256 } 256 }
257 257
258 ScreenConfigurationChanged(); 258 ScreenConfigurationChanged();
259 return true; 259 return true;
260 } 260 }
261 261
262 void VideoFrameCapturerMac::ReleaseBuffers() { 262 void ScreenCapturerMac::ReleaseBuffers() {
263 if (cgl_context_) { 263 if (cgl_context_) {
264 pixel_buffer_object_.Release(); 264 pixel_buffer_object_.Release();
265 CGLDestroyContext(cgl_context_); 265 CGLDestroyContext(cgl_context_);
266 cgl_context_ = NULL; 266 cgl_context_ = NULL;
267 } 267 }
268 // The buffers might be in use by the encoder, so don't delete them here. 268 // The buffers might be in use by the encoder, so don't delete them here.
269 // Instead, mark them as "needs update"; next time the buffers are used by 269 // Instead, mark them as "needs update"; next time the buffers are used by
270 // the capturer, they will be recreated if necessary. 270 // the capturer, they will be recreated if necessary.
271 queue_.SetAllFramesNeedUpdate(); 271 queue_.SetAllFramesNeedUpdate();
272 } 272 }
273 273
274 void VideoFrameCapturerMac::Start(Delegate* delegate) { 274 void ScreenCapturerMac::Start(Delegate* delegate) {
275 DCHECK(delegate_ == NULL); 275 DCHECK(delegate_ == NULL);
276 276
277 delegate_ = delegate; 277 delegate_ = delegate;
278 278
279 // Create power management assertions to wake the display and prevent it from 279 // Create power management assertions to wake the display and prevent it from
280 // going to sleep on user idle. 280 // going to sleep on user idle.
281 // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above 281 // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above
282 // instead of the following two assertions. 282 // instead of the following two assertions.
283 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, 283 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
284 kIOPMAssertionLevelOn, 284 kIOPMAssertionLevelOn,
285 CFSTR("Chrome Remote Desktop connection active"), 285 CFSTR("Chrome Remote Desktop connection active"),
286 &power_assertion_id_display_); 286 &power_assertion_id_display_);
287 // This assertion ensures that the display is woken up if it already asleep 287 // This assertion ensures that the display is woken up if it already asleep
288 // (as used by Apple Remote Desktop). 288 // (as used by Apple Remote Desktop).
289 IOPMAssertionCreateWithName(CFSTR("UserIsActive"), 289 IOPMAssertionCreateWithName(CFSTR("UserIsActive"),
290 kIOPMAssertionLevelOn, 290 kIOPMAssertionLevelOn,
291 CFSTR("Chrome Remote Desktop connection active"), 291 CFSTR("Chrome Remote Desktop connection active"),
292 &power_assertion_id_user_); 292 &power_assertion_id_user_);
293 } 293 }
294 294
295 void VideoFrameCapturerMac::Stop() { 295 void ScreenCapturerMac::Stop() {
296 if (power_assertion_id_display_ != kIOPMNullAssertionID) { 296 if (power_assertion_id_display_ != kIOPMNullAssertionID) {
297 IOPMAssertionRelease(power_assertion_id_display_); 297 IOPMAssertionRelease(power_assertion_id_display_);
298 power_assertion_id_display_ = kIOPMNullAssertionID; 298 power_assertion_id_display_ = kIOPMNullAssertionID;
299 } 299 }
300 if (power_assertion_id_user_ != kIOPMNullAssertionID) { 300 if (power_assertion_id_user_ != kIOPMNullAssertionID) {
301 IOPMAssertionRelease(power_assertion_id_user_); 301 IOPMAssertionRelease(power_assertion_id_user_);
302 power_assertion_id_user_ = kIOPMNullAssertionID; 302 power_assertion_id_user_ = kIOPMNullAssertionID;
303 } 303 }
304 } 304 }
305 305
306 void VideoFrameCapturerMac::InvalidateRegion(const SkRegion& invalid_region) { 306 void ScreenCapturerMac::InvalidateRegion(const SkRegion& invalid_region) {
307 helper_.InvalidateRegion(invalid_region); 307 helper_.InvalidateRegion(invalid_region);
308 } 308 }
309 309
310 void VideoFrameCapturerMac::CaptureFrame() { 310 void ScreenCapturerMac::CaptureFrame() {
311 // Only allow captures when the display configuration is not occurring. 311 // Only allow captures when the display configuration is not occurring.
312 scoped_refptr<CaptureData> data; 312 scoped_refptr<ScreenCaptureData> data;
313 313
314 base::Time capture_start_time = base::Time::Now(); 314 base::Time capture_start_time = base::Time::Now();
315 315
316 // Wait until the display configuration is stable. If one or more displays 316 // Wait until the display configuration is stable. If one or more displays
317 // are reconfiguring then |display_configuration_capture_event_| will not be 317 // are reconfiguring then |display_configuration_capture_event_| will not be
318 // set until the reconfiguration completes. 318 // set until the reconfiguration completes.
319 // TODO(wez): Replace this with an early-exit (See crbug.com/104542). 319 // TODO(wez): Replace this with an early-exit (See crbug.com/104542).
320 CHECK(display_configuration_capture_event_.TimedWait( 320 CHECK(display_configuration_capture_event_.TimedWait(
321 base::TimeDelta::FromSeconds( 321 base::TimeDelta::FromSeconds(
322 kDisplayConfigurationEventTimeoutInSeconds))); 322 kDisplayConfigurationEventTimeoutInSeconds)));
323 323
324 SkRegion region; 324 SkRegion region;
325 helper_.SwapInvalidRegion(&region); 325 helper_.SwapInvalidRegion(&region);
326 326
327 // If the current buffer is from an older generation then allocate a new one. 327 // If the current buffer is from an older generation then allocate a new one.
328 // Note that we can't reallocate other buffers at this point, since the caller 328 // Note that we can't reallocate other buffers at this point, since the caller
329 // may still be reading from them. 329 // may still be reading from them.
330 if (queue_.current_frame_needs_update()) { 330 if (queue_.current_frame_needs_update()) {
331 scoped_ptr<VideoFrameMac> buffer(new VideoFrameMac( 331 scoped_ptr<ScreenCaptureFrameMac> buffer(new ScreenCaptureFrameMac(
332 SkISize::Make(desktop_bounds_.width(), desktop_bounds_.height()))); 332 SkISize::Make(desktop_bounds_.width(), desktop_bounds_.height())));
333 queue_.ReplaceCurrentFrame(buffer.PassAs<VideoFrame>()); 333 queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>());
334 } 334 }
335 335
336 VideoFrame* current_buffer = queue_.current_frame(); 336 ScreenCaptureFrame* current_buffer = queue_.current_frame();
337 337
338 bool flip = false; // GL capturers need flipping. 338 bool flip = false; // GL capturers need flipping.
339 if (base::mac::IsOSLionOrLater()) { 339 if (base::mac::IsOSLionOrLater()) {
340 // Lion requires us to use their new APIs for doing screen capture. These 340 // Lion requires us to use their new APIs for doing screen capture. These
341 // APIS currently crash on 10.6.8 if there is no monitor attached. 341 // APIS currently crash on 10.6.8 if there is no monitor attached.
342 CgBlitPostLion(*current_buffer, region); 342 CgBlitPostLion(*current_buffer, region);
343 } else if (cgl_context_) { 343 } else if (cgl_context_) {
344 flip = true; 344 flip = true;
345 if (pixel_buffer_object_.get() != 0) { 345 if (pixel_buffer_object_.get() != 0) {
346 GlBlitFast(*current_buffer, region); 346 GlBlitFast(*current_buffer, region);
347 } else { 347 } else {
348 // See comment in ScopedPixelBufferObject::Init about why the slow 348 // See comment in ScopedPixelBufferObject::Init about why the slow
349 // path is always used on 10.5. 349 // path is always used on 10.5.
350 GlBlitSlow(*current_buffer); 350 GlBlitSlow(*current_buffer);
351 } 351 }
352 } else { 352 } else {
353 CgBlitPreLion(*current_buffer, region); 353 CgBlitPreLion(*current_buffer, region);
354 } 354 }
355 355
356 uint8* buffer = current_buffer->pixels(); 356 uint8* buffer = current_buffer->pixels();
357 int stride = current_buffer->bytes_per_row(); 357 int stride = current_buffer->bytes_per_row();
358 if (flip) { 358 if (flip) {
359 stride = -stride; 359 stride = -stride;
360 buffer += (current_buffer->dimensions().height() - 1) * 360 buffer += (current_buffer->dimensions().height() - 1) *
361 current_buffer->bytes_per_row(); 361 current_buffer->bytes_per_row();
362 } 362 }
363 363
364 data = new CaptureData(buffer, stride, current_buffer->dimensions()); 364 data = new ScreenCaptureData(buffer, stride, current_buffer->dimensions());
365 data->set_dpi(static_cast<VideoFrameMac*>(current_buffer)->dpi()); 365 data->set_dpi(static_cast<ScreenCaptureFrameMac*>(current_buffer)->dpi());
366 data->mutable_dirty_region() = region; 366 data->mutable_dirty_region() = region;
367 367
368 helper_.set_size_most_recent(data->size()); 368 helper_.set_size_most_recent(data->size());
369 369
370 // Signal that we are done capturing data from the display framebuffer, 370 // Signal that we are done capturing data from the display framebuffer,
371 // and accessing display structures. 371 // and accessing display structures.
372 display_configuration_capture_event_.Signal(); 372 display_configuration_capture_event_.Signal();
373 373
374 // Capture the current cursor shape and notify |delegate_| if it has changed. 374 // Capture the current cursor shape and notify |delegate_| if it has changed.
375 CaptureCursor(); 375 CaptureCursor();
376 376
377 // Move the capture frame buffer queue on to the next buffer. 377 // Move the capture frame buffer queue on to the next buffer.
378 queue_.DoneWithCurrentFrame(); 378 queue_.DoneWithCurrentFrame();
379 379
380 data->set_capture_time_ms( 380 data->set_capture_time_ms(
381 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); 381 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
382 delegate_->OnCaptureCompleted(data); 382 delegate_->OnCaptureCompleted(data);
383 } 383 }
384 384
385 void VideoFrameCapturerMac::CaptureCursor() { 385 void ScreenCapturerMac::CaptureCursor() {
386 NSCursor* cursor = [NSCursor currentSystemCursor]; 386 NSCursor* cursor = [NSCursor currentSystemCursor];
387 if (cursor == nil) { 387 if (cursor == nil) {
388 return; 388 return;
389 } 389 }
390 390
391 NSImage* nsimage = [cursor image]; 391 NSImage* nsimage = [cursor image];
392 NSPoint hotspot = [cursor hotSpot]; 392 NSPoint hotspot = [cursor hotSpot];
393 NSSize size = [nsimage size]; 393 NSSize size = [nsimage size];
394 CGImageRef image = [nsimage CGImageForProposedRect:NULL 394 CGImageRef image = [nsimage CGImageForProposedRect:NULL
395 context:nil 395 context:nil
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 // Create a MouseCursorShape that describes the cursor and pass it to 451 // Create a MouseCursorShape that describes the cursor and pass it to
452 // the client. 452 // the client.
453 scoped_ptr<MouseCursorShape> cursor_shape(new MouseCursorShape()); 453 scoped_ptr<MouseCursorShape> cursor_shape(new MouseCursorShape());
454 cursor_shape->size.set(size.width, size.height); 454 cursor_shape->size.set(size.width, size.height);
455 cursor_shape->hotspot.set(hotspot.x, hotspot.y); 455 cursor_shape->hotspot.set(hotspot.x, hotspot.y);
456 cursor_shape->data.assign(cursor_src_data, cursor_src_data + data_size); 456 cursor_shape->data.assign(cursor_src_data, cursor_src_data + data_size);
457 457
458 delegate_->OnCursorShapeChanged(cursor_shape.Pass()); 458 delegate_->OnCursorShapeChanged(cursor_shape.Pass());
459 } 459 }
460 460
461 void VideoFrameCapturerMac::GlBlitFast(const VideoFrame& buffer, 461 void ScreenCapturerMac::GlBlitFast(const ScreenCaptureFrame& buffer,
462 const SkRegion& region) { 462 const SkRegion& region) {
463 const int buffer_height = buffer.dimensions().height(); 463 const int buffer_height = buffer.dimensions().height();
464 const int buffer_width = buffer.dimensions().width(); 464 const int buffer_width = buffer.dimensions().width();
465 465
466 // Clip to the size of our current screen. 466 // Clip to the size of our current screen.
467 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); 467 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height);
468 if (queue_.previous_frame()) { 468 if (queue_.previous_frame()) {
469 // We are doing double buffer for the capture data so we just need to copy 469 // We are doing double buffer for the capture data so we just need to copy
470 // the invalid region from the previous capture in the current buffer. 470 // the invalid region from the previous capture in the current buffer.
471 // TODO(hclam): We can reduce the amount of copying here by subtracting 471 // TODO(hclam): We can reduce the amount of copying here by subtracting
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 // If glUnmapBuffer returns false, then the contents of the data store are 518 // If glUnmapBuffer returns false, then the contents of the data store are
519 // undefined. This might be because the screen mode has changed, in which 519 // undefined. This might be because the screen mode has changed, in which
520 // case it will be recreated in ScreenConfigurationChanged, but releasing 520 // case it will be recreated in ScreenConfigurationChanged, but releasing
521 // the object here is the best option. Capturing will fall back on 521 // the object here is the best option. Capturing will fall back on
522 // GlBlitSlow until such time as the pixel buffer object is recreated. 522 // GlBlitSlow until such time as the pixel buffer object is recreated.
523 pixel_buffer_object_.Release(); 523 pixel_buffer_object_.Release();
524 } 524 }
525 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); 525 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
526 } 526 }
527 527
528 void VideoFrameCapturerMac::GlBlitSlow(const VideoFrame& buffer) { 528 void ScreenCapturerMac::GlBlitSlow(const ScreenCaptureFrame& buffer) {
529 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_; 529 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_;
530 glReadBuffer(GL_FRONT); 530 glReadBuffer(GL_FRONT);
531 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 531 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
532 glPixelStorei(GL_PACK_ALIGNMENT, 4); // Force 4-byte alignment. 532 glPixelStorei(GL_PACK_ALIGNMENT, 4); // Force 4-byte alignment.
533 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 533 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
534 glPixelStorei(GL_PACK_SKIP_ROWS, 0); 534 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
535 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 535 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
536 // Read a block of pixels from the frame buffer. 536 // Read a block of pixels from the frame buffer.
537 glReadPixels(0, 0, buffer.dimensions().width(), buffer.dimensions().height(), 537 glReadPixels(0, 0, buffer.dimensions().width(), buffer.dimensions().height(),
538 GL_BGRA, GL_UNSIGNED_BYTE, buffer.pixels()); 538 GL_BGRA, GL_UNSIGNED_BYTE, buffer.pixels());
539 glPopClientAttrib(); 539 glPopClientAttrib();
540 } 540 }
541 541
542 void VideoFrameCapturerMac::CgBlitPreLion(const VideoFrame& buffer, 542 void ScreenCapturerMac::CgBlitPreLion(const ScreenCaptureFrame& buffer,
543 const SkRegion& region) { 543 const SkRegion& region) {
544 const int buffer_height = buffer.dimensions().height(); 544 const int buffer_height = buffer.dimensions().height();
545 545
546 // Copy the entire contents of the previous capture buffer, to capture over. 546 // Copy the entire contents of the previous capture buffer, to capture over.
547 // TODO(wez): Get rid of this as per crbug.com/145064, or implement 547 // TODO(wez): Get rid of this as per crbug.com/145064, or implement
548 // crbug.com/92354. 548 // crbug.com/92354.
549 if (queue_.previous_frame()) { 549 if (queue_.previous_frame()) {
550 memcpy(buffer.pixels(), 550 memcpy(buffer.pixels(),
551 queue_.previous_frame()->pixels(), 551 queue_.previous_frame()->pixels(),
552 buffer.bytes_per_row() * buffer_height); 552 buffer.bytes_per_row() * buffer_height);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 CopyRect(display_base_address, 585 CopyRect(display_base_address,
586 src_bytes_per_row, 586 src_bytes_per_row,
587 out_ptr, 587 out_ptr,
588 buffer.bytes_per_row(), 588 buffer.bytes_per_row(),
589 src_bytes_per_pixel, 589 src_bytes_per_pixel,
590 i.rect()); 590 i.rect());
591 } 591 }
592 } 592 }
593 } 593 }
594 594
595 void VideoFrameCapturerMac::CgBlitPostLion(const VideoFrame& buffer, 595 void ScreenCapturerMac::CgBlitPostLion(const ScreenCaptureFrame& buffer,
596 const SkRegion& region) { 596 const SkRegion& region) {
597 const int buffer_height = buffer.dimensions().height(); 597 const int buffer_height = buffer.dimensions().height();
598 598
599 // Copy the entire contents of the previous capture buffer, to capture over. 599 // Copy the entire contents of the previous capture buffer, to capture over.
600 // TODO(wez): Get rid of this as per crbug.com/145064, or implement 600 // TODO(wez): Get rid of this as per crbug.com/145064, or implement
601 // crbug.com/92354. 601 // crbug.com/92354.
602 if (queue_.previous_frame()) { 602 if (queue_.previous_frame()) {
603 memcpy(buffer.pixels(), 603 memcpy(buffer.pixels(),
604 queue_.previous_frame()->pixels(), 604 queue_.previous_frame()->pixels(),
605 buffer.bytes_per_row() * buffer_height); 605 buffer.bytes_per_row() * buffer_height);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 CopyRect(display_base_address, 645 CopyRect(display_base_address,
646 src_bytes_per_row, 646 src_bytes_per_row,
647 out_ptr, 647 out_ptr,
648 buffer.bytes_per_row(), 648 buffer.bytes_per_row(),
649 src_bytes_per_pixel, 649 src_bytes_per_pixel,
650 i.rect()); 650 i.rect());
651 } 651 }
652 } 652 }
653 } 653 }
654 654
655 void VideoFrameCapturerMac::ScreenConfigurationChanged() { 655 void ScreenCapturerMac::ScreenConfigurationChanged() {
656 // Release existing buffers, which will be of the wrong size. 656 // Release existing buffers, which will be of the wrong size.
657 ReleaseBuffers(); 657 ReleaseBuffers();
658 658
659 // Clear the dirty region, in case the display is down-sizing. 659 // Clear the dirty region, in case the display is down-sizing.
660 helper_.ClearInvalidRegion(); 660 helper_.ClearInvalidRegion();
661 661
662 // Fetch the list if active displays and calculate their bounds. 662 // Fetch the list if active displays and calculate their bounds.
663 CGDisplayCount display_count; 663 CGDisplayCount display_count;
664 CGError error = CGGetActiveDisplayList(0, NULL, &display_count); 664 CGError error = CGGetActiveDisplayList(0, NULL, &display_count);
665 CHECK_EQ(error, CGDisplayNoErr); 665 CHECK_EQ(error, CGDisplayNoErr);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 DCHECK_EQ(err, kCGLNoError); 746 DCHECK_EQ(err, kCGLNoError);
747 CGLDestroyPixelFormat(pixel_format); 747 CGLDestroyPixelFormat(pixel_format);
748 (*cgl_set_full_screen_)(cgl_context_); 748 (*cgl_set_full_screen_)(cgl_context_);
749 CGLSetCurrentContext(cgl_context_); 749 CGLSetCurrentContext(cgl_context_);
750 750
751 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() * 751 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() *
752 sizeof(uint32_t); 752 sizeof(uint32_t);
753 pixel_buffer_object_.Init(cgl_context_, buffer_size); 753 pixel_buffer_object_.Init(cgl_context_, buffer_size);
754 } 754 }
755 755
756 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, 756 void ScreenCapturerMac::ScreenRefresh(CGRectCount count,
757 const CGRect* rect_array) { 757 const CGRect* rect_array) {
758 if (desktop_bounds_.isEmpty()) { 758 if (desktop_bounds_.isEmpty()) {
759 return; 759 return;
760 } 760 }
761 SkIRect skirect_array[count]; 761 SkIRect skirect_array[count];
762 for (CGRectCount i = 0; i < count; ++i) { 762 for (CGRectCount i = 0; i < count; ++i) {
763 skirect_array[i] = CGRectToSkIRect(rect_array[i]); 763 skirect_array[i] = CGRectToSkIRect(rect_array[i]);
764 skirect_array[i].offset(-desktop_bounds_.left(), -desktop_bounds_.top()); 764 skirect_array[i].offset(-desktop_bounds_.left(), -desktop_bounds_.top());
765 } 765 }
766 SkRegion region; 766 SkRegion region;
767 region.setRects(skirect_array, count); 767 region.setRects(skirect_array, count);
768 InvalidateRegion(region); 768 InvalidateRegion(region);
769 } 769 }
770 770
771 void VideoFrameCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta, 771 void ScreenCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
772 size_t count, 772 size_t count,
773 const CGRect* rect_array) { 773 const CGRect* rect_array) {
774 SkIRect skirect_array[count]; 774 SkIRect skirect_array[count];
775 for (CGRectCount i = 0; i < count; ++i) { 775 for (CGRectCount i = 0; i < count; ++i) {
776 CGRect rect = rect_array[i]; 776 CGRect rect = rect_array[i];
777 rect = CGRectOffset(rect, delta.dX, delta.dY); 777 rect = CGRectOffset(rect, delta.dX, delta.dY);
778 skirect_array[i] = CGRectToSkIRect(rect); 778 skirect_array[i] = CGRectToSkIRect(rect);
779 skirect_array[i].offset(-desktop_bounds_.left(), -desktop_bounds_.top()); 779 skirect_array[i].offset(-desktop_bounds_.left(), -desktop_bounds_.top());
780 } 780 }
781 SkRegion region; 781 SkRegion region;
782 region.setRects(skirect_array, count); 782 region.setRects(skirect_array, count);
783 InvalidateRegion(region); 783 InvalidateRegion(region);
784 } 784 }
785 785
786 void VideoFrameCapturerMac::DisplaysReconfigured( 786 void ScreenCapturerMac::DisplaysReconfigured(
787 CGDirectDisplayID display, 787 CGDirectDisplayID display,
788 CGDisplayChangeSummaryFlags flags) { 788 CGDisplayChangeSummaryFlags flags) {
789 if (flags & kCGDisplayBeginConfigurationFlag) { 789 if (flags & kCGDisplayBeginConfigurationFlag) {
790 if (reconfiguring_displays_.empty()) { 790 if (reconfiguring_displays_.empty()) {
791 // If this is the first display to start reconfiguring then wait on 791 // If this is the first display to start reconfiguring then wait on
792 // |display_configuration_capture_event_| to block the capture thread 792 // |display_configuration_capture_event_| to block the capture thread
793 // from accessing display memory until the reconfiguration completes. 793 // from accessing display memory until the reconfiguration completes.
794 CHECK(display_configuration_capture_event_.TimedWait( 794 CHECK(display_configuration_capture_event_.TimedWait(
795 base::TimeDelta::FromSeconds( 795 base::TimeDelta::FromSeconds(
796 kDisplayConfigurationEventTimeoutInSeconds))); 796 kDisplayConfigurationEventTimeoutInSeconds)));
797 } 797 }
798 798
799 reconfiguring_displays_.insert(display); 799 reconfiguring_displays_.insert(display);
800 } else { 800 } else {
801 reconfiguring_displays_.erase(display); 801 reconfiguring_displays_.erase(display);
802 802
803 if (reconfiguring_displays_.empty()) { 803 if (reconfiguring_displays_.empty()) {
804 // If no other displays are reconfiguring then refresh capturer data 804 // If no other displays are reconfiguring then refresh capturer data
805 // structures and un-block the capturer thread. 805 // structures and un-block the capturer thread.
806 ScreenConfigurationChanged(); 806 ScreenConfigurationChanged();
807 display_configuration_capture_event_.Signal(); 807 display_configuration_capture_event_.Signal();
808 } 808 }
809 } 809 }
810 } 810 }
811 811
812 void VideoFrameCapturerMac::ScreenRefreshCallback(CGRectCount count, 812 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count,
813 const CGRect* rect_array, 813 const CGRect* rect_array,
814 void* user_parameter) { 814 void* user_parameter) {
815 VideoFrameCapturerMac* capturer = reinterpret_cast<VideoFrameCapturerMac*>( 815 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
816 user_parameter); 816 user_parameter);
817 if (capturer->desktop_bounds_.isEmpty()) { 817 if (capturer->desktop_bounds_.isEmpty()) {
818 capturer->ScreenConfigurationChanged(); 818 capturer->ScreenConfigurationChanged();
819 } 819 }
820 capturer->ScreenRefresh(count, rect_array); 820 capturer->ScreenRefresh(count, rect_array);
821 } 821 }
822 822
823 void VideoFrameCapturerMac::ScreenUpdateMoveCallback( 823 void ScreenCapturerMac::ScreenUpdateMoveCallback(
824 CGScreenUpdateMoveDelta delta, 824 CGScreenUpdateMoveDelta delta,
825 size_t count, 825 size_t count,
826 const CGRect* rect_array, 826 const CGRect* rect_array,
827 void* user_parameter) { 827 void* user_parameter) {
828 VideoFrameCapturerMac* capturer = reinterpret_cast<VideoFrameCapturerMac*>( 828 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
829 user_parameter); 829 user_parameter);
830 capturer->ScreenUpdateMove(delta, count, rect_array); 830 capturer->ScreenUpdateMove(delta, count, rect_array);
831 } 831 }
832 832
833 void VideoFrameCapturerMac::DisplaysReconfiguredCallback( 833 void ScreenCapturerMac::DisplaysReconfiguredCallback(
834 CGDirectDisplayID display, 834 CGDirectDisplayID display,
835 CGDisplayChangeSummaryFlags flags, 835 CGDisplayChangeSummaryFlags flags,
836 void* user_parameter) { 836 void* user_parameter) {
837 VideoFrameCapturerMac* capturer = reinterpret_cast<VideoFrameCapturerMac*>( 837 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
838 user_parameter); 838 user_parameter);
839 capturer->DisplaysReconfigured(display, flags); 839 capturer->DisplaysReconfigured(display, flags);
840 } 840 }
841 841
842 } // namespace 842 } // namespace
843 843
844 // static 844 // static
845 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::Create() { 845 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
846 scoped_ptr<VideoFrameCapturerMac> capturer(new VideoFrameCapturerMac()); 846 scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac());
847 if (!capturer->Init()) 847 if (!capturer->Init())
848 capturer.reset(); 848 capturer.reset();
849 return capturer.PassAs<VideoFrameCapturer>(); 849 return capturer.PassAs<ScreenCapturer>();
850 } 850 }
851 851
852 // static 852 // static
853 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::CreateWithFactory( 853 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithFactory(
854 SharedBufferFactory* shared_buffer_factory) { 854 SharedBufferFactory* shared_buffer_factory) {
855 NOTIMPLEMENTED(); 855 NOTIMPLEMENTED();
856 return scoped_ptr<VideoFrameCapturer>(); 856 return scoped_ptr<ScreenCapturer>();
857 } 857 }
858 858
859 } // namespace remoting 859 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698