OLD | NEW |
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/host/video_frame_capturer.h" | 5 #include "remoting/host/video_frame_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> |
(...skipping 19 matching lines...) Expand all Loading... |
30 SkIRect CGRectToSkIRect(const CGRect& rect) { | 30 SkIRect CGRectToSkIRect(const CGRect& rect) { |
31 SkIRect sk_rect = { | 31 SkIRect sk_rect = { |
32 SkScalarRound(rect.origin.x), | 32 SkScalarRound(rect.origin.x), |
33 SkScalarRound(rect.origin.y), | 33 SkScalarRound(rect.origin.y), |
34 SkScalarRound(rect.origin.x + rect.size.width), | 34 SkScalarRound(rect.origin.x + rect.size.width), |
35 SkScalarRound(rect.origin.y + rect.size.height) | 35 SkScalarRound(rect.origin.y + rect.size.height) |
36 }; | 36 }; |
37 return sk_rect; | 37 return sk_rect; |
38 } | 38 } |
39 | 39 |
40 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) | |
41 // Possibly remove VideoFrameCapturerMac::CgBlitPreLion as well depending on | |
42 // performance of VideoFrameCapturerMac::CgBlitPostLion on 10.6. | |
43 #error No longer need to import CGDisplayCreateImage. | |
44 #else | |
45 // Declared here because CGDisplayCreateImage does not exist in the 10.5 SDK, | |
46 // which we are currently compiling against, and it is required on 10.7 to do | |
47 // screen capture. | |
48 typedef CGImageRef (*CGDisplayCreateImageFunc)(CGDirectDisplayID displayID); | |
49 #endif | |
50 | |
51 // The amount of time allowed for displays to reconfigure. | 40 // The amount of time allowed for displays to reconfigure. |
52 const int64 kDisplayReconfigurationTimeoutInSeconds = 10; | 41 const int64 kDisplayReconfigurationTimeoutInSeconds = 10; |
53 | 42 |
54 class scoped_pixel_buffer_object { | 43 class scoped_pixel_buffer_object { |
55 public: | 44 public: |
56 scoped_pixel_buffer_object(); | 45 scoped_pixel_buffer_object(); |
57 ~scoped_pixel_buffer_object(); | 46 ~scoped_pixel_buffer_object(); |
58 | 47 |
59 bool Init(CGLContextObj cgl_context, int size_in_bytes); | 48 bool Init(CGLContextObj cgl_context, int size_in_bytes); |
60 void Release(); | 49 void Release(); |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // Contains an invalid region from the previous capture. | 225 // Contains an invalid region from the previous capture. |
237 SkRegion last_invalid_region_; | 226 SkRegion last_invalid_region_; |
238 | 227 |
239 // Format of pixels returned in buffer. | 228 // Format of pixels returned in buffer. |
240 media::VideoFrame::Format pixel_format_; | 229 media::VideoFrame::Format pixel_format_; |
241 | 230 |
242 // Acts as a critical section around our display configuration data | 231 // Acts as a critical section around our display configuration data |
243 // structures. Specifically cgl_context_ and pixel_buffer_object_. | 232 // structures. Specifically cgl_context_ and pixel_buffer_object_. |
244 base::WaitableEvent display_configuration_capture_event_; | 233 base::WaitableEvent display_configuration_capture_event_; |
245 | 234 |
246 // Will be non-null on lion. | |
247 CGDisplayCreateImageFunc display_create_image_func_; | |
248 | |
249 // Power management assertion to prevent the screen from sleeping. | 235 // Power management assertion to prevent the screen from sleeping. |
250 IOPMAssertionID power_assertion_id_display_; | 236 IOPMAssertionID power_assertion_id_display_; |
251 | 237 |
252 // Power management assertion to indicate that the user is active. | 238 // Power management assertion to indicate that the user is active. |
253 IOPMAssertionID power_assertion_id_user_; | 239 IOPMAssertionID power_assertion_id_user_; |
254 | 240 |
255 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); | 241 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); |
256 }; | 242 }; |
257 | 243 |
258 VideoFrameCapturerMac::VideoFrameCapturerMac() | 244 VideoFrameCapturerMac::VideoFrameCapturerMac() |
259 : cgl_context_(NULL), | 245 : cgl_context_(NULL), |
260 current_buffer_(0), | 246 current_buffer_(0), |
261 last_buffer_(NULL), | 247 last_buffer_(NULL), |
262 pixel_format_(media::VideoFrame::RGB32), | 248 pixel_format_(media::VideoFrame::RGB32), |
263 display_configuration_capture_event_(false, true), | 249 display_configuration_capture_event_(false, true), |
264 display_create_image_func_(NULL), | |
265 power_assertion_id_display_(kIOPMNullAssertionID), | 250 power_assertion_id_display_(kIOPMNullAssertionID), |
266 power_assertion_id_user_(kIOPMNullAssertionID) { | 251 power_assertion_id_user_(kIOPMNullAssertionID) { |
267 } | 252 } |
268 | 253 |
269 VideoFrameCapturerMac::~VideoFrameCapturerMac() { | 254 VideoFrameCapturerMac::~VideoFrameCapturerMac() { |
270 ReleaseBuffers(); | 255 ReleaseBuffers(); |
271 CGUnregisterScreenRefreshCallback( | 256 CGUnregisterScreenRefreshCallback( |
272 VideoFrameCapturerMac::ScreenRefreshCallback, this); | 257 VideoFrameCapturerMac::ScreenRefreshCallback, this); |
273 CGScreenUnregisterMoveCallback( | 258 CGScreenUnregisterMoveCallback( |
274 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); | 259 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); |
(...skipping 18 matching lines...) Expand all Loading... |
293 LOG(ERROR) << "CGScreenRegisterMoveCallback " << err; | 278 LOG(ERROR) << "CGScreenRegisterMoveCallback " << err; |
294 return false; | 279 return false; |
295 } | 280 } |
296 err = CGDisplayRegisterReconfigurationCallback( | 281 err = CGDisplayRegisterReconfigurationCallback( |
297 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); | 282 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); |
298 if (err != kCGErrorSuccess) { | 283 if (err != kCGErrorSuccess) { |
299 LOG(ERROR) << "CGDisplayRegisterReconfigurationCallback " << err; | 284 LOG(ERROR) << "CGDisplayRegisterReconfigurationCallback " << err; |
300 return false; | 285 return false; |
301 } | 286 } |
302 | 287 |
303 if (base::mac::IsOSLionOrLater()) { | |
304 display_create_image_func_ = | |
305 reinterpret_cast<CGDisplayCreateImageFunc>( | |
306 dlsym(RTLD_NEXT, "CGDisplayCreateImage")); | |
307 if (!display_create_image_func_) { | |
308 LOG(ERROR) << "Unable to load CGDisplayCreateImage on Lion"; | |
309 return false; | |
310 } | |
311 } | |
312 ScreenConfigurationChanged(); | 288 ScreenConfigurationChanged(); |
313 return true; | 289 return true; |
314 } | 290 } |
315 | 291 |
316 void VideoFrameCapturerMac::ReleaseBuffers() { | 292 void VideoFrameCapturerMac::ReleaseBuffers() { |
317 if (cgl_context_) { | 293 if (cgl_context_) { |
318 pixel_buffer_object_.Release(); | 294 pixel_buffer_object_.Release(); |
319 CGLDestroyContext(cgl_context_); | 295 CGLDestroyContext(cgl_context_); |
320 cgl_context_ = NULL; | 296 cgl_context_ = NULL; |
321 } | 297 } |
322 // The buffers might be in use by the encoder, so don't delete them here. | 298 // The buffers might be in use by the encoder, so don't delete them here. |
323 // Instead, mark them as "needs update"; next time the buffers are used by | 299 // Instead, mark them as "needs update"; next time the buffers are used by |
324 // the capturer, they will be recreated if necessary. | 300 // the capturer, they will be recreated if necessary. |
325 for (int i = 0; i < kNumBuffers; ++i) { | 301 for (int i = 0; i < kNumBuffers; ++i) { |
326 buffers_[i].set_needs_update(); | 302 buffers_[i].set_needs_update(); |
327 } | 303 } |
328 } | 304 } |
329 | 305 |
330 void VideoFrameCapturerMac::Start(const CursorShapeChangedCallback& callback) { | 306 void VideoFrameCapturerMac::Start(const CursorShapeChangedCallback& callback) { |
331 cursor_shape_changed_callback_ = callback; | 307 cursor_shape_changed_callback_ = callback; |
332 | 308 |
333 // Create power management assertions to wake the display and prevent it from | 309 // Create power management assertions to wake the display and prevent it from |
334 // going to sleep on user idle. | 310 // going to sleep on user idle. |
335 IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep, | 311 // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above |
336 kIOPMAssertionLevelOn, | 312 // instead of the following two assertions. |
337 &power_assertion_id_display_); | 313 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, |
338 IOPMAssertionCreate(CFSTR("UserIsActive"), | 314 kIOPMAssertionLevelOn, |
339 kIOPMAssertionLevelOn, | 315 CFSTR("Chrome Remote Desktop connection active"), |
340 &power_assertion_id_user_); | 316 &power_assertion_id_display_); |
| 317 // This assertion ensures that the display is woken up if it already asleep |
| 318 // (as used by Apple Remote Desktop). |
| 319 IOPMAssertionCreateWithName(CFSTR("UserIsActive"), |
| 320 kIOPMAssertionLevelOn, |
| 321 CFSTR("Chrome Remote Desktop connection active"), |
| 322 &power_assertion_id_user_); |
341 } | 323 } |
342 | 324 |
343 void VideoFrameCapturerMac::Stop() { | 325 void VideoFrameCapturerMac::Stop() { |
344 if (power_assertion_id_display_ != kIOPMNullAssertionID) { | 326 if (power_assertion_id_display_ != kIOPMNullAssertionID) { |
345 IOPMAssertionRelease(power_assertion_id_display_); | 327 IOPMAssertionRelease(power_assertion_id_display_); |
346 power_assertion_id_display_ = kIOPMNullAssertionID; | 328 power_assertion_id_display_ = kIOPMNullAssertionID; |
347 } | 329 } |
348 if (power_assertion_id_user_ != kIOPMNullAssertionID) { | 330 if (power_assertion_id_user_ != kIOPMNullAssertionID) { |
349 IOPMAssertionRelease(power_assertion_id_user_); | 331 IOPMAssertionRelease(power_assertion_id_user_); |
350 power_assertion_id_user_ = kIOPMNullAssertionID; | 332 power_assertion_id_user_ = kIOPMNullAssertionID; |
(...skipping 15 matching lines...) Expand all Loading... |
366 | 348 |
367 // Critical section shared with DisplaysReconfigured(...). | 349 // Critical section shared with DisplaysReconfigured(...). |
368 CHECK(display_configuration_capture_event_.TimedWait( | 350 CHECK(display_configuration_capture_event_.TimedWait( |
369 base::TimeDelta::FromSeconds(kDisplayReconfigurationTimeoutInSeconds))); | 351 base::TimeDelta::FromSeconds(kDisplayReconfigurationTimeoutInSeconds))); |
370 SkRegion region; | 352 SkRegion region; |
371 helper_.SwapInvalidRegion(®ion); | 353 helper_.SwapInvalidRegion(®ion); |
372 VideoFrameBuffer& current_buffer = buffers_[current_buffer_]; | 354 VideoFrameBuffer& current_buffer = buffers_[current_buffer_]; |
373 current_buffer.Update(); | 355 current_buffer.Update(); |
374 | 356 |
375 bool flip = false; // GL capturers need flipping. | 357 bool flip = false; // GL capturers need flipping. |
376 if (display_create_image_func_ != NULL) { | 358 if (base::mac::IsOSLionOrLater()) { |
377 // Lion requires us to use their new APIs for doing screen capture. | 359 // Lion requires us to use their new APIs for doing screen capture. These |
| 360 // APIS currently crash on 10.6.8 if there is no monitor attached. |
378 CgBlitPostLion(current_buffer, region); | 361 CgBlitPostLion(current_buffer, region); |
379 } else if (cgl_context_) { | 362 } else if (cgl_context_) { |
380 flip = true; | 363 flip = true; |
381 if (pixel_buffer_object_.get() != 0) { | 364 if (pixel_buffer_object_.get() != 0) { |
382 GlBlitFast(current_buffer, region); | 365 GlBlitFast(current_buffer, region); |
383 } else { | 366 } else { |
384 // See comment in scoped_pixel_buffer_object::Init about why the slow | 367 // See comment in scoped_pixel_buffer_object::Init about why the slow |
385 // path is always used on 10.5. | 368 // path is always used on 10.5. |
386 GlBlitSlow(current_buffer); | 369 GlBlitSlow(current_buffer); |
387 } | 370 } |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 const int buffer_height = buffer.size().height(); | 567 const int buffer_height = buffer.size().height(); |
585 const int buffer_width = buffer.size().width(); | 568 const int buffer_width = buffer.size().width(); |
586 | 569 |
587 // Clip to the size of our current screen. | 570 // Clip to the size of our current screen. |
588 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); | 571 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); |
589 | 572 |
590 if (last_buffer_) | 573 if (last_buffer_) |
591 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); | 574 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); |
592 last_buffer_ = buffer.ptr(); | 575 last_buffer_ = buffer.ptr(); |
593 CGDirectDisplayID main_display = CGMainDisplayID(); | 576 CGDirectDisplayID main_display = CGMainDisplayID(); |
| 577 #pragma clang diagnostic push |
| 578 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
594 uint8* display_base_address = | 579 uint8* display_base_address = |
595 reinterpret_cast<uint8*>(CGDisplayBaseAddress(main_display)); | 580 reinterpret_cast<uint8*>(CGDisplayBaseAddress(main_display)); |
596 CHECK(display_base_address); | 581 CHECK(display_base_address); |
597 int src_bytes_per_row = CGDisplayBytesPerRow(main_display); | 582 int src_bytes_per_row = CGDisplayBytesPerRow(main_display); |
598 int src_bytes_per_pixel = CGDisplayBitsPerPixel(main_display) / 8; | 583 int src_bytes_per_pixel = CGDisplayBitsPerPixel(main_display) / 8; |
| 584 #pragma clang diagnostic pop |
599 // TODO(hclam): We can reduce the amount of copying here by subtracting | 585 // TODO(hclam): We can reduce the amount of copying here by subtracting |
600 // |capturer_helper_|s region from |last_invalid_region_|. | 586 // |capturer_helper_|s region from |last_invalid_region_|. |
601 // http://crbug.com/92354 | 587 // http://crbug.com/92354 |
602 for(SkRegion::Iterator i(region); !i.done(); i.next()) { | 588 for(SkRegion::Iterator i(region); !i.done(); i.next()) { |
603 SkIRect copy_rect = i.rect(); | 589 SkIRect copy_rect = i.rect(); |
604 if (copy_rect.intersect(clip_rect)) { | 590 if (copy_rect.intersect(clip_rect)) { |
605 CopyRect(display_base_address, | 591 CopyRect(display_base_address, |
606 src_bytes_per_row, | 592 src_bytes_per_row, |
607 buffer.ptr(), | 593 buffer.ptr(), |
608 buffer.bytes_per_row(), | 594 buffer.bytes_per_row(), |
609 src_bytes_per_pixel, | 595 src_bytes_per_pixel, |
610 copy_rect); | 596 copy_rect); |
611 } | 597 } |
612 } | 598 } |
613 } | 599 } |
614 | 600 |
615 void VideoFrameCapturerMac::CgBlitPostLion(const VideoFrameBuffer& buffer, | 601 void VideoFrameCapturerMac::CgBlitPostLion(const VideoFrameBuffer& buffer, |
616 const SkRegion& region) { | 602 const SkRegion& region) { |
617 const int buffer_height = buffer.size().height(); | 603 const int buffer_height = buffer.size().height(); |
618 const int buffer_width = buffer.size().width(); | 604 const int buffer_width = buffer.size().width(); |
619 | 605 |
620 // Clip to the size of our current screen. | 606 // Clip to the size of our current screen. |
621 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); | 607 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); |
622 | 608 |
623 if (last_buffer_) | 609 if (last_buffer_) |
624 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); | 610 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); |
625 last_buffer_ = buffer.ptr(); | 611 last_buffer_ = buffer.ptr(); |
626 CGDirectDisplayID display = CGMainDisplayID(); | 612 CGDirectDisplayID display = CGMainDisplayID(); |
627 base::mac::ScopedCFTypeRef<CGImageRef> image( | 613 base::mac::ScopedCFTypeRef<CGImageRef> image( |
628 display_create_image_func_(display)); | 614 CGDisplayCreateImage(display)); |
629 if (image.get() == NULL) | 615 if (image.get() == NULL) |
630 return; | 616 return; |
631 CGDataProviderRef provider = CGImageGetDataProvider(image); | 617 CGDataProviderRef provider = CGImageGetDataProvider(image); |
632 base::mac::ScopedCFTypeRef<CFDataRef> data(CGDataProviderCopyData(provider)); | 618 base::mac::ScopedCFTypeRef<CFDataRef> data(CGDataProviderCopyData(provider)); |
633 if (data.get() == NULL) | 619 if (data.get() == NULL) |
634 return; | 620 return; |
635 const uint8* display_base_address = CFDataGetBytePtr(data); | 621 const uint8* display_base_address = CFDataGetBytePtr(data); |
636 int src_bytes_per_row = CGImageGetBytesPerRow(image); | 622 int src_bytes_per_row = CGImageGetBytesPerRow(image); |
637 int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8; | 623 int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8; |
638 // TODO(hclam): We can reduce the amount of copying here by subtracting | 624 // TODO(hclam): We can reduce the amount of copying here by subtracting |
(...skipping 19 matching lines...) Expand all Loading... |
658 void VideoFrameCapturerMac::ScreenConfigurationChanged() { | 644 void VideoFrameCapturerMac::ScreenConfigurationChanged() { |
659 ReleaseBuffers(); | 645 ReleaseBuffers(); |
660 helper_.ClearInvalidRegion(); | 646 helper_.ClearInvalidRegion(); |
661 last_buffer_ = NULL; | 647 last_buffer_ = NULL; |
662 | 648 |
663 CGDirectDisplayID mainDevice = CGMainDisplayID(); | 649 CGDirectDisplayID mainDevice = CGMainDisplayID(); |
664 int width = CGDisplayPixelsWide(mainDevice); | 650 int width = CGDisplayPixelsWide(mainDevice); |
665 int height = CGDisplayPixelsHigh(mainDevice); | 651 int height = CGDisplayPixelsHigh(mainDevice); |
666 helper_.InvalidateScreen(SkISize::Make(width, height)); | 652 helper_.InvalidateScreen(SkISize::Make(width, height)); |
667 | 653 |
668 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { | 654 if (base::mac::IsOSLionOrLater()) { |
669 VLOG(3) << "OpenGL support not available."; | 655 LOG(INFO) << "Using CgBlitPostLion."; |
670 return; | |
671 } | |
672 | |
673 if (display_create_image_func_ != NULL) { | |
674 // No need for any OpenGL support on Lion | 656 // No need for any OpenGL support on Lion |
675 return; | 657 return; |
676 } | 658 } |
677 | 659 |
| 660 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { |
| 661 LOG(INFO) << "Using CgBlitPreLion."; |
| 662 return; |
| 663 } |
| 664 |
| 665 LOG(INFO) << "Using GlBlit"; |
| 666 |
678 CGLPixelFormatAttribute attributes[] = { | 667 CGLPixelFormatAttribute attributes[] = { |
679 kCGLPFAFullScreen, | 668 kCGLPFAFullScreen, |
680 kCGLPFADisplayMask, | 669 kCGLPFADisplayMask, |
681 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), | 670 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), |
682 (CGLPixelFormatAttribute)0 | 671 (CGLPixelFormatAttribute)0 |
683 }; | 672 }; |
684 CGLPixelFormatObj pixel_format = NULL; | 673 CGLPixelFormatObj pixel_format = NULL; |
685 GLint matching_pixel_format_count = 0; | 674 GLint matching_pixel_format_count = 0; |
686 CGLError err = CGLChoosePixelFormat(attributes, | 675 CGLError err = CGLChoosePixelFormat(attributes, |
687 &pixel_format, | 676 &pixel_format, |
688 &matching_pixel_format_count); | 677 &matching_pixel_format_count); |
689 DCHECK_EQ(err, kCGLNoError); | 678 DCHECK_EQ(err, kCGLNoError); |
690 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); | 679 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); |
691 DCHECK_EQ(err, kCGLNoError); | 680 DCHECK_EQ(err, kCGLNoError); |
692 CGLDestroyPixelFormat(pixel_format); | 681 CGLDestroyPixelFormat(pixel_format); |
693 CGLSetFullScreen(cgl_context_); | 682 CGLSetFullScreenOnDisplay(cgl_context_, |
| 683 CGDisplayIDToOpenGLDisplayMask(mainDevice)); |
694 CGLSetCurrentContext(cgl_context_); | 684 CGLSetCurrentContext(cgl_context_); |
695 | 685 |
696 size_t buffer_size = width * height * sizeof(uint32_t); | 686 size_t buffer_size = width * height * sizeof(uint32_t); |
697 pixel_buffer_object_.Init(cgl_context_, buffer_size); | 687 pixel_buffer_object_.Init(cgl_context_, buffer_size); |
698 } | 688 } |
699 | 689 |
700 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, | 690 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, |
701 const CGRect* rect_array) { | 691 const CGRect* rect_array) { |
702 SkIRect skirect_array[count]; | 692 SkIRect skirect_array[count]; |
703 for (CGRectCount i = 0; i < count; ++i) { | 693 for (CGRectCount i = 0; i < count; ++i) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 VideoFrameCapturer* VideoFrameCapturer::Create() { | 764 VideoFrameCapturer* VideoFrameCapturer::Create() { |
775 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); | 765 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); |
776 if (!capturer->Init()) { | 766 if (!capturer->Init()) { |
777 delete capturer; | 767 delete capturer; |
778 capturer = NULL; | 768 capturer = NULL; |
779 } | 769 } |
780 return capturer; | 770 return capturer; |
781 } | 771 } |
782 | 772 |
783 } // namespace remoting | 773 } // namespace remoting |
OLD | NEW |