LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/desktop_capture - app_capturer_x11.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 123 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             : *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
       3             : *
       4             : *  Use of this source code is governed by a BSD-style license
       5             : *  that can be found in the LICENSE file in the root of the source
       6             : *  tree. An additional intellectual property rights grant can be found
       7             : *  in the file PATENTS.  All contributing project authors may
       8             : *  be found in the AUTHORS file in the root of the source tree.
       9             : */
      10             : #include "webrtc/modules/desktop_capture/app_capturer.h"
      11             : #include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
      12             : #include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
      13             : 
      14             : #include <assert.h>
      15             : #include <string.h>
      16             : #include <X11/Xatom.h>
      17             : #include <X11/extensions/Xcomposite.h>
      18             : #include <X11/extensions/Xrender.h>
      19             : #include <X11/Xutil.h>
      20             : #include <X11/Xregion.h>
      21             : 
      22             : #include <algorithm>
      23             : 
      24             : #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
      25             : #include "webrtc/modules/desktop_capture/desktop_frame.h"
      26             : #include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
      27             : #include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
      28             : #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
      29             : #include "webrtc/system_wrappers/include/logging.h"
      30             : 
      31             : namespace webrtc {
      32             : 
      33             : namespace {
      34             : 
      35           0 : class ScreenCapturerProxy : DesktopCapturer::Callback {
      36             : public:
      37           0 :   ScreenCapturerProxy()
      38           0 :     : screen_capturer_(DesktopCapturer::CreateScreenCapturer(DesktopCaptureOptions::CreateDefault())) {
      39           0 :     screen_capturer_->SelectSource(kFullDesktopScreenId);
      40           0 :     screen_capturer_->Start(this);
      41           0 :   }
      42           0 :   void CaptureFrame() { screen_capturer_->CaptureFrame(); }
      43           0 :   std::unique_ptr<DesktopFrame> GetFrame() { return std::move(frame_); }
      44             : 
      45             :    // Callback interface
      46           0 :   virtual void OnCaptureResult(DesktopCapturer::Result result,
      47             :                                std::unique_ptr<DesktopFrame> frame) {
      48           0 :     frame_ = std::move(frame);
      49           0 :   }
      50             : 
      51             : protected:
      52             :   std::unique_ptr<DesktopCapturer> screen_capturer_;
      53             :   std::unique_ptr<DesktopFrame> frame_;
      54             : };
      55             : 
      56             : class AppCapturerLinux : public AppCapturer {
      57             : public:
      58             :   AppCapturerLinux(const DesktopCaptureOptions& options);
      59             :   virtual ~AppCapturerLinux();
      60             : 
      61             :   // AppCapturer interface.
      62             :   virtual bool GetAppList(AppList* apps) override;
      63             :   virtual bool SelectApp(ProcessId processId) override;
      64             :   virtual bool BringAppToFront() override;
      65             : 
      66             :   // DesktopCapturer interface.
      67             :   virtual void Start(Callback* callback) override;
      68             :   virtual void Stop() override;
      69             :   virtual void CaptureFrame() override;
      70           0 :   virtual bool SelectSource(SourceId id) override
      71             :   {
      72           0 :     return SelectApp(static_cast<ProcessId>(id));
      73             :   }
      74             : 
      75             : protected:
      76           0 :   Display* GetDisplay() { return x_display_->display(); }
      77             :   bool UpdateRegions();
      78             : 
      79             :   void FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame,Region rgn, uint32_t color);
      80             : private:
      81             :   Callback* callback_;
      82             :   ProcessId selected_process_;
      83             : 
      84             :   // Sample Mode
      85             :   ScreenCapturerProxy screen_capturer_proxy_;
      86             :   // Mask of foreground (non-app windows in front of selected)
      87             :   Region rgn_mask_;
      88             :   // Region of selected windows
      89             :   Region rgn_visual_;
      90             :   // Mask of background (desktop, non-app windows behind selected)
      91             :   Region rgn_background_;
      92             : 
      93             :   rtc::scoped_refptr<SharedXDisplay> x_display_;
      94             :   RTC_DISALLOW_COPY_AND_ASSIGN(AppCapturerLinux);
      95             : };
      96             : 
      97           0 : AppCapturerLinux::AppCapturerLinux(const DesktopCaptureOptions& options)
      98             :     : callback_(NULL),
      99             :       selected_process_(0),
     100           0 :       x_display_(options.x_display()) {
     101           0 :   rgn_mask_ = XCreateRegion();
     102           0 :   rgn_visual_ = XCreateRegion();
     103           0 :   rgn_background_ = XCreateRegion();
     104           0 : }
     105             : 
     106           0 : AppCapturerLinux::~AppCapturerLinux() {
     107           0 :   if (rgn_mask_) {
     108           0 :     XDestroyRegion(rgn_mask_);
     109             :   }
     110           0 :   if (rgn_visual_) {
     111           0 :     XDestroyRegion(rgn_visual_);
     112             :   }
     113           0 :   if (rgn_background_) {
     114           0 :     XDestroyRegion(rgn_background_);
     115             :   }
     116           0 : }
     117             : 
     118             : // AppCapturer interface.
     119           0 : bool AppCapturerLinux::GetAppList(AppList* apps) {
     120             :   // Implemented in DesktopDeviceInfo
     121           0 :   return true;
     122             : }
     123           0 : bool AppCapturerLinux::SelectApp(ProcessId processId) {
     124           0 :   selected_process_ = processId;
     125           0 :   return true;
     126             : }
     127           0 : bool AppCapturerLinux::BringAppToFront() {
     128             :   // Not implemented yet: See Bug 1036653
     129           0 :   return true;
     130             : }
     131             : 
     132             : // DesktopCapturer interface.
     133           0 : void AppCapturerLinux::Start(Callback* callback) {
     134           0 :   assert(!callback_);
     135           0 :   assert(callback);
     136             : 
     137           0 :   callback_ = callback;
     138           0 : }
     139             : 
     140           0 : void AppCapturerLinux::Stop() {
     141           0 :   callback_ = NULL;
     142           0 : }
     143             : 
     144           0 : void AppCapturerLinux::CaptureFrame() {
     145           0 :   XErrorTrap error_trap(GetDisplay());
     146             : 
     147             :   //Capture screen >> set root window as capture window
     148           0 :   screen_capturer_proxy_.CaptureFrame();
     149           0 :   std::unique_ptr<DesktopFrame> frame = std::move(screen_capturer_proxy_.GetFrame());
     150           0 :   if (frame) {
     151             : 
     152             :     // calculate app visual/foreground region
     153           0 :     UpdateRegions();
     154             : 
     155             :     // TODO: background/foreground mask colors should be configurable; see Bug 1054503
     156             :     // fill background with black
     157           0 :     FillDesktopFrameRegionWithColor(frame.get(), rgn_background_, 0xFF000000);
     158             : 
     159             :     // fill foreground with yellow
     160           0 :     FillDesktopFrameRegionWithColor(frame.get(), rgn_mask_, 0xFFFFFF00);
     161             :  }
     162             : 
     163             :   // trigger event
     164           0 :   if (callback_) {
     165           0 :     bool worked = error_trap.GetLastErrorAndDisable() == 0;
     166           0 :     DesktopCapturer::Result res = worked ? DesktopCapturer::Result::SUCCESS
     167           0 :                                          : DesktopCapturer::Result::ERROR_TEMPORARY;
     168           0 :     callback_->OnCaptureResult(res, std::move(frame));
     169             :   }
     170           0 : }
     171             : 
     172           0 : void AppCapturerLinux::FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame, Region rgn, uint32_t color) {
     173           0 :   XErrorTrap error_trap(GetDisplay());
     174             : 
     175           0 :   if (!pDesktopFrame) {
     176           0 :     return;
     177             :   }
     178           0 :   if (XEmptyRegion(rgn)) {
     179           0 :     return;
     180             :   }
     181             : 
     182           0 :   REGION * st_rgn = (REGION *)rgn;
     183           0 :   if(st_rgn && st_rgn->numRects > 0) {
     184           0 :     for (short i = 0; i < st_rgn->numRects; i++) {
     185           0 :       for (short j = st_rgn->rects[i].y1; j < st_rgn->rects[i].y2; j++) {
     186           0 :         uint32_t* dst_pos = reinterpret_cast<uint32_t*>(pDesktopFrame->data() + pDesktopFrame->stride() * j);
     187           0 :         for (short k = st_rgn->rects[i].x1; k < st_rgn->rects[i].x2; k++) {
     188           0 :           dst_pos[k] = color;
     189             :         }
     190             :       }
     191             :     }
     192             :   }
     193             : }
     194             : 
     195           0 : bool AppCapturerLinux::UpdateRegions() {
     196           0 :   XErrorTrap error_trap(GetDisplay());
     197             : 
     198           0 :   XSubtractRegion(rgn_visual_, rgn_visual_, rgn_visual_);
     199           0 :   XSubtractRegion(rgn_mask_, rgn_mask_, rgn_mask_);
     200           0 :   WindowUtilX11 window_util_x11(x_display_);
     201           0 :   int num_screens = XScreenCount(GetDisplay());
     202           0 :   for (int screen = 0; screen < num_screens; ++screen) {
     203           0 :     int nScreenCX = DisplayWidth(GetDisplay(), screen);
     204           0 :     int nScreenCY = DisplayHeight(GetDisplay(), screen);
     205             : 
     206             :     XRectangle  screen_rect;
     207           0 :     screen_rect.x = 0;
     208           0 :     screen_rect.y = 0;
     209           0 :     screen_rect.width = nScreenCX;
     210           0 :     screen_rect.height = nScreenCY;
     211             : 
     212           0 :     XUnionRectWithRegion(&screen_rect, rgn_background_, rgn_background_);
     213           0 :     XXorRegion(rgn_mask_, rgn_mask_, rgn_mask_);
     214           0 :     XXorRegion(rgn_visual_, rgn_visual_, rgn_visual_);
     215             : 
     216           0 :     ::Window root_window = XRootWindow(GetDisplay(), screen);
     217             :     ::Window parent;
     218             :     ::Window root_return;
     219             :     ::Window *children;
     220             :     unsigned int num_children;
     221           0 :     int status = XQueryTree(GetDisplay(), root_window, &root_return, &parent, &children, &num_children);
     222           0 :     if (status == 0) {
     223           0 :       LOG(LS_ERROR) << "Failed to query for child windows for screen " << screen;
     224           0 :       continue;
     225             :     }
     226           0 :     for (unsigned int i = 0; i < num_children; ++i) {
     227           0 :       ::Window app_window = window_util_x11.GetApplicationWindow(children[i]);
     228           0 :       if (!app_window) {
     229           0 :         continue;
     230             :       }
     231             : 
     232             :       // Get window region
     233             :       XRectangle  win_rect;
     234           0 :       window_util_x11.GetWindowRect(app_window, win_rect, true);
     235           0 :       if (win_rect.width <= 0 || win_rect.height <= 0) {
     236           0 :         continue;
     237             :       }
     238             : 
     239           0 :       Region win_rgn = XCreateRegion();
     240           0 :       XUnionRectWithRegion(&win_rect, win_rgn, win_rgn);
     241             :       // update rgn_visual_ , rgn_mask_,
     242           0 :       unsigned int processId = window_util_x11.GetWindowProcessID(app_window);
     243           0 :       if (processId != 0 && processId == selected_process_) {
     244           0 :         XUnionRegion(rgn_visual_, win_rgn, rgn_visual_);
     245           0 :         XSubtractRegion(rgn_mask_, win_rgn, rgn_mask_);
     246             :       } else {
     247           0 :         Region win_rgn_intersect = XCreateRegion();
     248           0 :         XIntersectRegion(rgn_visual_, win_rgn, win_rgn_intersect);
     249             : 
     250           0 :         XSubtractRegion(rgn_visual_, win_rgn_intersect, rgn_visual_);
     251           0 :         XUnionRegion(win_rgn_intersect, rgn_mask_, rgn_mask_);
     252             : 
     253           0 :         if (win_rgn_intersect) {
     254           0 :           XDestroyRegion(win_rgn_intersect);
     255             :         }
     256             :       }
     257           0 :       if (win_rgn) {
     258           0 :         XDestroyRegion(win_rgn);
     259             :       }
     260             :     }
     261             : 
     262           0 :     if (children) {
     263           0 :       XFree(children);
     264             :     }
     265             :   }
     266             : 
     267           0 :   XSubtractRegion(rgn_background_, rgn_visual_, rgn_background_);
     268             : 
     269           0 :   return true;
     270             : }
     271             : 
     272             : }  // namespace
     273             : 
     274             : // static
     275           0 : AppCapturer* AppCapturer::Create(const DesktopCaptureOptions& options) {
     276           0 :   return new AppCapturerLinux(options);
     277             : }
     278             : 
     279             : // static
     280           0 : std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawAppCapturer(
     281             :     const DesktopCaptureOptions& options) {
     282             : 
     283           0 :   if (!options.x_display())
     284           0 :     return nullptr;
     285             : 
     286           0 :   std::unique_ptr<AppCapturerLinux> capturer(new AppCapturerLinux(options));
     287             : 
     288           0 :   return std::unique_ptr<DesktopCapturer>(std::move(capturer));
     289             : }
     290             : 
     291             : }  // namespace webrtc

Generated by: LCOV version 1.13