1b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org/* 2b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * 4b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 5b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 6b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 7b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 8b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 9b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org */ 10b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 11b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/window_capturer.h" 12b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 1312dc1a38ca54a000e4fecfbc6d41138b895c9ca5pbos@webrtc.org#include <assert.h> 14eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include <ApplicationServices/ApplicationServices.h> 15886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org#include <Cocoa/Cocoa.h> 16eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include <CoreFoundation/CoreFoundation.h> 17b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 1812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/base/macutils.h" 1926b08605e2b99136fcc1cab0800234f469d6e236Peter Boström#include "webrtc/base/scoped_ref_ptr.h" 2012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h" 21b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 2212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" 2312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h" 2412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/window_list_utils.h" 2598f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/logging.h" 2698f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/tick_util.h" 27b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 28b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace webrtc { 29b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 30b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace { 31b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 3212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org// Returns true if the window exists. 33cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.orgbool IsWindowValid(CGWindowID id) { 34cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CFArrayRef window_id_array = 35cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL); 36cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CFArrayRef window_array = 37cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CGWindowListCreateDescriptionFromArray(window_id_array); 38cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org bool valid = window_array && CFArrayGetCount(window_array); 39cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CFRelease(window_id_array); 40cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org CFRelease(window_array); 41cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org 42cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org return valid; 43cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org} 44cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org 45b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgclass WindowCapturerMac : public WindowCapturer { 46b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org public: 4726b08605e2b99136fcc1cab0800234f469d6e236Peter Boström explicit WindowCapturerMac(rtc::scoped_refptr<FullScreenChromeWindowDetector> 4826b08605e2b99136fcc1cab0800234f469d6e236Peter Boström full_screen_chrome_window_detector); 49b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual ~WindowCapturerMac(); 50b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 51b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org // WindowCapturer interface. 5214665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org bool GetWindowList(WindowList* windows) override; 5314665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org bool SelectWindow(WindowId id) override; 5414665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org bool BringSelectedWindowToFront() override; 55b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 56b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org // DesktopCapturer interface. 5714665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org void Start(Callback* callback) override; 5814665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org void Capture(const DesktopRegion& region) override; 59b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 60b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org private: 61b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org Callback* callback_; 6212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 6312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org // The window being captured. 64eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGWindowID window_id_; 65b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 6626b08605e2b99136fcc1cab0800234f469d6e236Peter Boström rtc::scoped_refptr<FullScreenChromeWindowDetector> 6712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_; 6812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 693c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac); 70b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}; 71b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 7226b08605e2b99136fcc1cab0800234f469d6e236Peter BoströmWindowCapturerMac::WindowCapturerMac(rtc::scoped_refptr< 7326b08605e2b99136fcc1cab0800234f469d6e236Peter Boström FullScreenChromeWindowDetector> full_screen_chrome_window_detector) 74eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org : callback_(NULL), 7512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org window_id_(0), 7612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_(full_screen_chrome_window_detector) { 77b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 78b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 79b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerMac::~WindowCapturerMac() { 80b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 81b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 82b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::GetWindowList(WindowList* windows) { 83eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Only get on screen, non-desktop windows. 84eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFArrayRef window_array = CGWindowListCopyWindowInfo( 85eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, 86eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org kCGNullWindowID); 87eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (!window_array) 88eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return false; 89eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 90eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Check windows to make sure they have an id, title, and use window layer 91eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // other than 0. 92eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFIndex count = CFArrayGetCount(window_array); 93eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org for (CFIndex i = 0; i < count; ++i) { 94eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( 95eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFArrayGetValueAtIndex(window_array, i)); 96eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFStringRef window_title = reinterpret_cast<CFStringRef>( 97eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowName)); 98eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberRef window_id = reinterpret_cast<CFNumberRef>( 99eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowNumber)); 100eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberRef window_layer = reinterpret_cast<CFNumberRef>( 101eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowLayer)); 102eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (window_title && window_id && window_layer) { 103eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Skip windows with layer=0 (menu, dock). 104eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int layer; 105eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberGetValue(window_layer, kCFNumberIntType, &layer); 106eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (layer != 0) 107eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org continue; 108eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 109eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int id; 110eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberGetValue(window_id, kCFNumberIntType, &id); 111eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org WindowCapturer::Window window; 112eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window.id = id; 11312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (!rtc::ToUtf8(window_title, &(window.title)) || 114eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window.title.empty()) { 115eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org continue; 116eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 117eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org windows->push_back(window); 118eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 119eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 120eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 121eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_array); 122eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return true; 123b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 124b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 125b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::SelectWindow(WindowId id) { 126cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org if (!IsWindowValid(id)) 127eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return false; 128eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window_id_ = id; 129eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return true; 130b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 131b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 132886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.orgbool WindowCapturerMac::BringSelectedWindowToFront() { 133886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org if (!window_id_) 134886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return false; 135886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 136886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CGWindowID ids[1]; 137886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org ids[0] = window_id_; 138886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayRef window_id_array = 139886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL); 140886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 141886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayRef window_array = 142886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CGWindowListCreateDescriptionFromArray(window_id_array); 143886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org if (window_array == NULL || 0 == CFArrayGetCount(window_array)) { 144886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // Could not find the window. It might have been closed. 145886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org LOG(LS_INFO) << "Window not found"; 146886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_id_array); 147886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return false; 148886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org } 149886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 150886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( 151886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayGetValueAtIndex(window_array, 0)); 152886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFNumberRef pid_ref = reinterpret_cast<CFNumberRef>( 153886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFDictionaryGetValue(window, kCGWindowOwnerPID)); 154886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 155886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org int pid; 156886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFNumberGetValue(pid_ref, kCFNumberIntType, &pid); 157886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 158886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // TODO(jiayl): this will bring the process main window to the front. We 159886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // should find a way to bring only the window to the front. 160886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org bool result = 161886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org [[NSRunningApplication runningApplicationWithProcessIdentifier: pid] 162886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org activateWithOptions: NSApplicationActivateIgnoringOtherApps]; 163886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 164886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_id_array); 165886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_array); 166886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return result; 167886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org} 168886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 169b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Start(Callback* callback) { 170b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org assert(!callback_); 171b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org assert(callback); 172b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 173b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org callback_ = callback; 174b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 175b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 176b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Capture(const DesktopRegion& region) { 177cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org if (!IsWindowValid(window_id_)) { 178cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org callback_->OnCaptureCompleted(NULL); 179cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org return; 180cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org } 181cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org 18212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org CGWindowID on_screen_window = window_id_; 18312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_chrome_window_detector_) { 18412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org CGWindowID full_screen_window = 18512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); 18612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 18712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_window != kCGNullWindowID) 18812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org on_screen_window = full_screen_window; 18912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org } 19012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 191eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGImageRef window_image = CGWindowListCreateImage( 192eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGRectNull, kCGWindowListOptionIncludingWindow, 19312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org on_screen_window, kCGWindowImageBoundsIgnoreFraming); 194eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 195eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (!window_image) { 196eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 197eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return; 198eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 199eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 200eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int bits_per_pixel = CGImageGetBitsPerPixel(window_image); 201eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (bits_per_pixel != 32) { 202eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel; 203eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_image); 204eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 205eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return; 206eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 207eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 208eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int width = CGImageGetWidth(window_image); 209eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int height = CGImageGetHeight(window_image); 210eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGDataProviderRef provider = CGImageGetDataProvider(window_image); 2112df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org CFDataRef cf_data = CGDataProviderCopyData(provider); 2122df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopFrame* frame = new BasicDesktopFrame( 2132df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopSize(width, height)); 2142df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org 2152df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org int src_stride = CGImageGetBytesPerRow(window_image); 2162df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org const uint8_t* src_data = CFDataGetBytePtr(cf_data); 2172df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org for (int y = 0; y < height; ++y) { 2182df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y, 2192df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopFrame::kBytesPerPixel * width); 2202df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org } 2212df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org 2222df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org CFRelease(cf_data); 223eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_image); 224eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 225d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org frame->mutable_updated_region()->SetRect( 226d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org DesktopRect::MakeSize(frame->size())); 227d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org 228eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(frame); 22912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 23012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_chrome_window_detector_) 23112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_); 232b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 233b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 234b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} // namespace 235b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 236b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org// static 237894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { 23812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org return new WindowCapturerMac(options.full_screen_chrome_window_detector()); 239b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 240b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 241b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} // namespace webrtc 242