Bug 1036653 - Mac-specific support for app sharing, r=jesup,gcp

This commit is contained in:
Matthew A. Miller 2014-08-20 16:05:59 -06:00
Родитель 6830ad82b2
Коммит 2a30bda0e5
3 изменённых файлов: 147 добавлений и 28 удалений

Просмотреть файл

@ -8,13 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/desktop_capture/window_capturer.h"
#include "webrtc/modules/desktop_capture/app_capturer.h"
#include <assert.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <AppKit/AppKit.h>
#include "webrtc/modules/desktop_capture/window_capturer.h"
#include "webrtc/modules/desktop_capture/app_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/system_wrappers/interface/logging.h"
@ -30,7 +32,7 @@ class AppCapturerMac : public AppCapturer {
// AppCapturer interface.
virtual bool GetAppList(AppList* apps) OVERRIDE;
virtual bool SelectApp(ProcessId id) OVERRIDE;
virtual bool SelectApp(ProcessId processId) OVERRIDE;
virtual bool BringAppToFront() OVERRIDE;
// DesktopCapturer interface.
@ -53,19 +55,19 @@ AppCapturerMac::~AppCapturerMac() {
}
// AppCapturer interface.
bool AppCapturerMac::GetAppList(AppList* apps){
// Not implemented yet: See Bug 1036653
bool AppCapturerMac::GetAppList(AppList* apps) {
// handled by DesktopDeviceInfo
return true;
}
bool AppCapturerMac::SelectApp(ProcessId id){
// Not implemented yet: See Bug 1036653
bool AppCapturerMac::SelectApp(ProcessId processId) {
process_id_ = processId;
return true;
}
bool AppCapturerMac::BringAppToFront() {
// Not implemented yet: See Bug 1036653
return true;
return true;
}
// DesktopCapturer interface.
@ -77,7 +79,99 @@ void AppCapturerMac::Start(Callback* callback) {
}
void AppCapturerMac::Capture(const DesktopRegion& region) {
// Not implemented yet: See Bug 1036653
// Check that selected process exists
NSRunningApplication *ra = [NSRunningApplication runningApplicationWithProcessIdentifier:process_id_];
if (!ra) {
callback_->OnCaptureCompleted(NULL);
return;
}
#if defined(__LP64__)
#define CaptureWindowID int64_t
#else
#define CaptureWindowID CGWindowID
#endif
CFArrayRef windowInfos = CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
kCGNullWindowID);
CFIndex windowInfosCount = CFArrayGetCount(windowInfos);
CaptureWindowID *captureWindowList = new CaptureWindowID[windowInfosCount];
CFIndex captureWindowListCount = 0;
for (CFIndex idx = 0; idx < windowInfosCount; idx++) {
CFDictionaryRef info = reinterpret_cast<CFDictionaryRef>(
CFArrayGetValueAtIndex(windowInfos, idx));
CFNumberRef winOwner = reinterpret_cast<CFNumberRef>(
CFDictionaryGetValue(info, kCGWindowOwnerPID));
CFNumberRef winId = reinterpret_cast<CFNumberRef>(
CFDictionaryGetValue(info, kCGWindowNumber));
pid_t owner;
CFNumberGetValue(winOwner, kCFNumberIntType, &owner);
if (owner != process_id_) {
continue;
}
CGWindowID ident;
CFNumberGetValue(winId, kCFNumberIntType, &ident);
captureWindowList[captureWindowListCount++] = ident;
}
CFRelease(windowInfos);
// Check that window list is not empty
if (captureWindowListCount <= 0) {
delete [] captureWindowList;
callback_->OnCaptureCompleted(NULL);
return;
}
// Does not support multi-display; See bug 1037997.
CGRect rectCapturedDisplay = CGDisplayBounds(CGMainDisplayID());
// Capture all windows of selected process, bounded by desktop.
CFArrayRef windowIDsArray = CFArrayCreate(kCFAllocatorDefault,
(const void**)captureWindowList,
captureWindowListCount,
NULL);
CGImageRef app_image = CGWindowListCreateImageFromArray(rectCapturedDisplay,
windowIDsArray,
kCGWindowImageDefault);
CFRelease (windowIDsArray);
delete [] captureWindowList;
// Wrap raw data into DesktopFrame
if (!app_image) {
CFRelease(app_image);
callback_->OnCaptureCompleted(NULL);
return;
}
int bits_per_pixel = CGImageGetBitsPerPixel(app_image);
if (bits_per_pixel != 32) {
LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel;
CFRelease(app_image);
callback_->OnCaptureCompleted(NULL);
return;
}
int width = CGImageGetWidth(app_image);
int height = CGImageGetHeight(app_image);
DesktopFrame* frame = new BasicDesktopFrame(DesktopSize(width, height));
CGDataProviderRef provider = CGImageGetDataProvider(app_image);
CFDataRef cf_data = CGDataProviderCopyData(provider);
int src_stride = CGImageGetBytesPerRow(app_image);
const uint8_t* src_data = CFDataGetBytePtr(cf_data);
for (int y = 0; y < height; ++y) {
memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y,
DesktopFrame::kBytesPerPixel * width);
}
CFRelease(cf_data);
CFRelease(app_image);
callback_->OnCaptureCompleted(frame);
}
} // namespace

Просмотреть файл

@ -15,13 +15,14 @@ public:
DesktopDeviceInfoMac();
~DesktopDeviceInfoMac();
protected:
//DesktopDeviceInfo Interfaces
virtual int32_t Init();
virtual int32_t Refresh();
virtual void InitializeApplicationList() OVERRIDE;
virtual void InitializeScreenList() OVERRIDE;
private:
#if !defined(MULTI_MONITOR_SCREENSHARE)
int32_t MultiMonitorScreenshare();
void MultiMonitorScreenshare();
#endif
};

Просмотреть файл

@ -3,7 +3,10 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "webrtc/modules/desktop_capture/mac/desktop_device_info_mac.h"
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <unistd.h>
#include <stdio.h>
namespace webrtc {
@ -25,7 +28,7 @@ DesktopDeviceInfoMac::~DesktopDeviceInfoMac() {
}
#if !defined(MULTI_MONITOR_SCREENSHARE)
int32_t DesktopDeviceInfoMac::MultiMonitorScreenshare()
void DesktopDeviceInfoMac::MultiMonitorScreenshare()
{
DesktopDisplayDevice *pDesktopDeviceInfo = new DesktopDisplayDevice;
if (pDesktopDeviceInfo) {
@ -35,29 +38,50 @@ int32_t DesktopDeviceInfoMac::MultiMonitorScreenshare()
desktop_display_list_[pDesktopDeviceInfo->getScreenId()] = pDesktopDeviceInfo;
}
return 0;
}
#endif
int32_t DesktopDeviceInfoMac::Init() {
void DesktopDeviceInfoMac::InitializeScreenList() {
#if !defined(MULTI_MONITOR_SCREENSHARE)
MultiMonitorScreenshare();
#endif
initializeWindowList();
return 0;
}
void DesktopDeviceInfoMac::InitializeApplicationList() {
//List all running applications (excluding background processes).
int32_t DesktopDeviceInfoMac::Refresh() {
#if !defined(MULTI_MONITOR_SCREENSHARE)
desktop_display_list_.clear();
MultiMonitorScreenshare();
#endif
NSArray *running = [[NSWorkspace sharedWorkspace] runningApplications];
for (NSRunningApplication *ra in running) {
if (ra.activationPolicy != NSApplicationActivationPolicyRegular)
continue;
RefreshWindowList();
ProcessId pid = ra.processIdentifier;
if (pid == 0) {
continue;
}
if (pid == getpid()) {
continue;
}
return 0;
DesktopApplication *pDesktopApplication = new DesktopApplication;
if (!pDesktopApplication) {
continue;
}
pDesktopApplication->setProcessId(pid);
NSString *str;
str = [ra.executableURL absoluteString];
pDesktopApplication->setProcessPathName([str UTF8String]);
str = ra.localizedName;
pDesktopApplication->setProcessAppName([str UTF8String]);
char idStr[64];
snprintf(idStr, sizeof(idStr), "%ld", pDesktopApplication->getProcessId());
pDesktopApplication->setUniqueIdName(idStr);
desktop_application_list_[pDesktopApplication->getProcessId()] = pDesktopApplication;
}
}
} //namespace webrtc