window_capturer_mac.mm revision d402875fa50164c6533ef0f7b2098f73eb94b8a8
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" 1912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h" 20b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 2112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" 2212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h" 2312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/window_list_utils.h" 24eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h" 2512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/system_wrappers/interface/scoped_refptr.h" 2612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/system_wrappers/interface/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: 4712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org explicit WindowCapturerMac( 4812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org scoped_refptr<FullScreenChromeWindowDetector> 4912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector); 50b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual ~WindowCapturerMac(); 51b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 52b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org // WindowCapturer interface. 53b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual bool GetWindowList(WindowList* windows) OVERRIDE; 54b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual bool SelectWindow(WindowId id) OVERRIDE; 55886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org virtual bool BringSelectedWindowToFront() OVERRIDE; 56b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 57b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org // DesktopCapturer interface. 58b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual void Start(Callback* callback) OVERRIDE; 59b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org virtual void Capture(const DesktopRegion& region) OVERRIDE; 60b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 61b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org private: 62b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org Callback* callback_; 6312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 6412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org // The window being captured. 65eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGWindowID window_id_; 66b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 6712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org scoped_refptr<FullScreenChromeWindowDetector> 6812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_; 6912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 70b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac); 71b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}; 72b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 7312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.orgWindowCapturerMac::WindowCapturerMac( 7412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org scoped_refptr<FullScreenChromeWindowDetector> 7512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector) 76eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org : callback_(NULL), 7712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org window_id_(0), 7812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_(full_screen_chrome_window_detector) { 79b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 80b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 81b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerMac::~WindowCapturerMac() { 82b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 83b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 84b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::GetWindowList(WindowList* windows) { 85eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Only get on screen, non-desktop windows. 86eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFArrayRef window_array = CGWindowListCopyWindowInfo( 87eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, 88eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org kCGNullWindowID); 89eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (!window_array) 90eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return false; 91eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 92eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Check windows to make sure they have an id, title, and use window layer 93eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // other than 0. 94eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFIndex count = CFArrayGetCount(window_array); 95eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org for (CFIndex i = 0; i < count; ++i) { 96eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( 97eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFArrayGetValueAtIndex(window_array, i)); 98eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFStringRef window_title = reinterpret_cast<CFStringRef>( 99eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowName)); 100eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberRef window_id = reinterpret_cast<CFNumberRef>( 101eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowNumber)); 102eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberRef window_layer = reinterpret_cast<CFNumberRef>( 103eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowLayer)); 104eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (window_title && window_id && window_layer) { 105eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org // Skip windows with layer=0 (menu, dock). 106eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int layer; 107eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberGetValue(window_layer, kCFNumberIntType, &layer); 108eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (layer != 0) 109eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org continue; 110eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 111eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int id; 112eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFNumberGetValue(window_id, kCFNumberIntType, &id); 113eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org WindowCapturer::Window window; 114eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window.id = id; 11512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (!rtc::ToUtf8(window_title, &(window.title)) || 116eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window.title.empty()) { 117eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org continue; 118eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 119eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org windows->push_back(window); 120eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 121eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 122eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 123eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_array); 124eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return true; 125b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 126b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 127b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::SelectWindow(WindowId id) { 128cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org if (!IsWindowValid(id)) 129eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return false; 130eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org window_id_ = id; 131eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return true; 132b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 133b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 134886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.orgbool WindowCapturerMac::BringSelectedWindowToFront() { 135886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org if (!window_id_) 136886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return false; 137886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 138886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CGWindowID ids[1]; 139886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org ids[0] = window_id_; 140886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayRef window_id_array = 141886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL); 142886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 143886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayRef window_array = 144886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CGWindowListCreateDescriptionFromArray(window_id_array); 145886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org if (window_array == NULL || 0 == CFArrayGetCount(window_array)) { 146886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // Could not find the window. It might have been closed. 147886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org LOG(LS_INFO) << "Window not found"; 148886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_id_array); 149886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return false; 150886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org } 151886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 152886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( 153886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFArrayGetValueAtIndex(window_array, 0)); 154886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFNumberRef pid_ref = reinterpret_cast<CFNumberRef>( 155886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFDictionaryGetValue(window, kCGWindowOwnerPID)); 156886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 157886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org int pid; 158886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFNumberGetValue(pid_ref, kCFNumberIntType, &pid); 159886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 160886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // TODO(jiayl): this will bring the process main window to the front. We 161886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org // should find a way to bring only the window to the front. 162886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org bool result = 163886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org [[NSRunningApplication runningApplicationWithProcessIdentifier: pid] 164886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org activateWithOptions: NSApplicationActivateIgnoringOtherApps]; 165886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 166886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_id_array); 167886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org CFRelease(window_array); 168886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org return result; 169886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org} 170886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org 171b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Start(Callback* callback) { 172b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org assert(!callback_); 173b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org assert(callback); 174b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 175b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org callback_ = callback; 176b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 177b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 178b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Capture(const DesktopRegion& region) { 179cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org if (!IsWindowValid(window_id_)) { 180cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org callback_->OnCaptureCompleted(NULL); 181cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org return; 182cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org } 183cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org 18412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org CGWindowID on_screen_window = window_id_; 18512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_chrome_window_detector_) { 18612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org CGWindowID full_screen_window = 18712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); 18812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 18912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_window != kCGNullWindowID) 19012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org on_screen_window = full_screen_window; 19112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org } 19212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 193eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGImageRef window_image = CGWindowListCreateImage( 194eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGRectNull, kCGWindowListOptionIncludingWindow, 19512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org on_screen_window, kCGWindowImageBoundsIgnoreFraming); 196eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 197eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (!window_image) { 198eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 199eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return; 200eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 201eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 202eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int bits_per_pixel = CGImageGetBitsPerPixel(window_image); 203eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org if (bits_per_pixel != 32) { 204eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel; 205eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_image); 206eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 207eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org return; 208eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org } 209eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 210eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int width = CGImageGetWidth(window_image); 211eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org int height = CGImageGetHeight(window_image); 212eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CGDataProviderRef provider = CGImageGetDataProvider(window_image); 2132df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org CFDataRef cf_data = CGDataProviderCopyData(provider); 2142df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopFrame* frame = new BasicDesktopFrame( 2152df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopSize(width, height)); 2162df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org 2172df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org int src_stride = CGImageGetBytesPerRow(window_image); 2182df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org const uint8_t* src_data = CFDataGetBytePtr(cf_data); 2192df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org for (int y = 0; y < height; ++y) { 2202df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y, 2212df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org DesktopFrame::kBytesPerPixel * width); 2222df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org } 2232df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org 2242df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org CFRelease(cf_data); 225eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org CFRelease(window_image); 226eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org 227d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org frame->mutable_updated_region()->SetRect( 228d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org DesktopRect::MakeSize(frame->size())); 229d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org 230eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org callback_->OnCaptureCompleted(frame); 23112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org 23212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org if (full_screen_chrome_window_detector_) 23312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_); 234b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 235b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 236b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} // namespace 237b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 238b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org// static 239894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { 24012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org return new WindowCapturerMac(options.full_screen_chrome_window_detector()); 241b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} 242b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org 243b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org} // namespace webrtc 244