LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/desktop_capture/x11 - x_server_pixel_buffer.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 199 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 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             : 
      11             : #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
      12             : 
      13             : #include <assert.h>
      14             : #include <string.h>
      15             : #include <sys/shm.h>
      16             : 
      17             : #include "webrtc/modules/desktop_capture/desktop_frame.h"
      18             : #include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
      19             : #include "webrtc/system_wrappers/include/logging.h"
      20             : 
      21             : namespace {
      22             : 
      23             : // Returns the number of bits |mask| has to be shifted left so its last
      24             : // (most-significant) bit set becomes the most-significant bit of the word.
      25             : // When |mask| is 0 the function returns 31.
      26           0 : uint32_t MaskToShift(uint32_t mask) {
      27           0 :   int shift = 0;
      28           0 :   if ((mask & 0xffff0000u) == 0) {
      29           0 :     mask <<= 16;
      30           0 :     shift += 16;
      31             :   }
      32           0 :   if ((mask & 0xff000000u) == 0) {
      33           0 :     mask <<= 8;
      34           0 :     shift += 8;
      35             :   }
      36           0 :   if ((mask & 0xf0000000u) == 0) {
      37           0 :     mask <<= 4;
      38           0 :     shift += 4;
      39             :   }
      40           0 :   if ((mask & 0xc0000000u) == 0) {
      41           0 :     mask <<= 2;
      42           0 :     shift += 2;
      43             :   }
      44           0 :   if ((mask & 0x80000000u) == 0)
      45           0 :     shift += 1;
      46             : 
      47           0 :   return shift;
      48             : }
      49             : 
      50             : // Returns true if |image| is in RGB format.
      51           0 : bool IsXImageRGBFormat(XImage* image) {
      52           0 :   return image->bits_per_pixel == 32 &&
      53           0 :       image->red_mask == 0xff0000 &&
      54           0 :       image->green_mask == 0xff00 &&
      55           0 :       image->blue_mask == 0xff;
      56             : }
      57             : 
      58             : }  // namespace
      59             : 
      60             : namespace webrtc {
      61             : 
      62           0 : XServerPixelBuffer::XServerPixelBuffer() {}
      63             : 
      64           0 : XServerPixelBuffer::~XServerPixelBuffer() {
      65           0 :   Release();
      66           0 : }
      67             : 
      68           0 : void XServerPixelBuffer::Release() {
      69           0 :   if (x_image_) {
      70           0 :     XDestroyImage(x_image_);
      71           0 :     x_image_ = NULL;
      72             :   }
      73           0 :   if (shm_pixmap_) {
      74           0 :     XFreePixmap(display_, shm_pixmap_);
      75           0 :     shm_pixmap_ = 0;
      76             :   }
      77           0 :   if (shm_gc_) {
      78           0 :     XFreeGC(display_, shm_gc_);
      79           0 :     shm_gc_ = NULL;
      80             :   }
      81           0 :   if (shm_segment_info_) {
      82           0 :     if (shm_segment_info_->shmaddr != reinterpret_cast<char*>(-1))
      83           0 :       shmdt(shm_segment_info_->shmaddr);
      84           0 :     if (shm_segment_info_->shmid != -1)
      85           0 :       shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
      86           0 :     delete shm_segment_info_;
      87           0 :     shm_segment_info_ = NULL;
      88             :   }
      89           0 :   window_ = 0;
      90           0 : }
      91             : 
      92           0 : bool XServerPixelBuffer::Init(Display* display, Window window) {
      93           0 :   Release();
      94           0 :   display_ = display;
      95             : 
      96             :   XWindowAttributes attributes;
      97             :   {
      98           0 :     XErrorTrap error_trap(display_);
      99           0 :     if (!XGetWindowAttributes(display_, window, &attributes) ||
     100           0 :         error_trap.GetLastErrorAndDisable() != 0) {
     101           0 :       return false;
     102             :     }
     103             :   }
     104             : 
     105           0 :   window_size_ = DesktopSize(attributes.width, attributes.height);
     106           0 :   window_ = window;
     107           0 :   InitShm(attributes);
     108             : 
     109           0 :   return true;
     110             : }
     111             : 
     112           0 : void XServerPixelBuffer::InitShm(const XWindowAttributes& attributes) {
     113           0 :   Visual* default_visual = attributes.visual;
     114           0 :   int default_depth = attributes.depth;
     115             : 
     116             :   int major, minor;
     117             :   Bool have_pixmaps;
     118           0 :   if (!XShmQueryVersion(display_, &major, &minor, &have_pixmaps)) {
     119             :     // Shared memory not supported. CaptureRect will use the XImage API instead.
     120           0 :     return;
     121             :   }
     122             : 
     123           0 :   bool using_shm = false;
     124           0 :   shm_segment_info_ = new XShmSegmentInfo;
     125           0 :   shm_segment_info_->shmid = -1;
     126           0 :   shm_segment_info_->shmaddr = reinterpret_cast<char*>(-1);
     127           0 :   shm_segment_info_->readOnly = False;
     128           0 :   x_image_ = XShmCreateImage(display_, default_visual, default_depth, ZPixmap,
     129           0 :                              0, shm_segment_info_, window_size_.width(),
     130           0 :                              window_size_.height());
     131           0 :   if (x_image_) {
     132           0 :     shm_segment_info_->shmid = shmget(
     133           0 :         IPC_PRIVATE, x_image_->bytes_per_line * x_image_->height,
     134             :         IPC_CREAT | 0600);
     135           0 :     if (shm_segment_info_->shmid != -1) {
     136           0 :       shm_segment_info_->shmaddr = x_image_->data =
     137           0 :           reinterpret_cast<char*>(shmat(shm_segment_info_->shmid, 0, 0));
     138           0 :       if (x_image_->data != reinterpret_cast<char*>(-1)) {
     139           0 :         XErrorTrap error_trap(display_);
     140           0 :         using_shm = XShmAttach(display_, shm_segment_info_);
     141           0 :         XSync(display_, False);
     142           0 :         if (error_trap.GetLastErrorAndDisable() != 0)
     143           0 :           using_shm = false;
     144           0 :         if (using_shm) {
     145           0 :           LOG(LS_VERBOSE) << "Using X shared memory segment "
     146           0 :                           << shm_segment_info_->shmid;
     147             :         }
     148             :       }
     149             :     } else {
     150           0 :       LOG(LS_WARNING) << "Failed to get shared memory segment. "
     151           0 :                       "Performance may be degraded.";
     152             :     }
     153             :   }
     154             : 
     155           0 :   if (!using_shm) {
     156           0 :     LOG(LS_WARNING) << "Not using shared memory. Performance may be degraded.";
     157           0 :     Release();
     158           0 :     return;
     159             :   }
     160             : 
     161           0 :   if (have_pixmaps)
     162           0 :     have_pixmaps = InitPixmaps(default_depth);
     163             : 
     164           0 :   shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
     165           0 :   shm_segment_info_->shmid = -1;
     166             : 
     167           0 :   LOG(LS_VERBOSE) << "Using X shared memory extension v"
     168             :                   << major << "." << minor
     169           0 :                   << " with" << (have_pixmaps ? "" : "out") << " pixmaps.";
     170             : }
     171             : 
     172           0 : bool XServerPixelBuffer::InitPixmaps(int depth) {
     173           0 :   if (XShmPixmapFormat(display_) != ZPixmap)
     174           0 :     return false;
     175             : 
     176             :   {
     177           0 :     XErrorTrap error_trap(display_);
     178           0 :     shm_pixmap_ = XShmCreatePixmap(display_, window_,
     179           0 :                                    shm_segment_info_->shmaddr,
     180             :                                    shm_segment_info_,
     181           0 :                                    window_size_.width(),
     182           0 :                                    window_size_.height(), depth);
     183           0 :     XSync(display_, False);
     184           0 :     if (error_trap.GetLastErrorAndDisable() != 0) {
     185             :       // |shm_pixmap_| is not not valid because the request was not processed
     186             :       // by the X Server, so zero it.
     187           0 :       shm_pixmap_ = 0;
     188           0 :       return false;
     189             :     }
     190             :   }
     191             : 
     192             :   {
     193           0 :     XErrorTrap error_trap(display_);
     194             :     XGCValues shm_gc_values;
     195           0 :     shm_gc_values.subwindow_mode = IncludeInferiors;
     196           0 :     shm_gc_values.graphics_exposures = False;
     197           0 :     shm_gc_ = XCreateGC(display_, window_,
     198             :                         GCSubwindowMode | GCGraphicsExposures,
     199             :                         &shm_gc_values);
     200           0 :     XSync(display_, False);
     201           0 :     if (error_trap.GetLastErrorAndDisable() != 0) {
     202           0 :       XFreePixmap(display_, shm_pixmap_);
     203           0 :       shm_pixmap_ = 0;
     204           0 :       shm_gc_ = 0;  // See shm_pixmap_ comment above.
     205           0 :       return false;
     206             :     }
     207             :   }
     208             : 
     209           0 :   return true;
     210             : }
     211             : 
     212           0 : bool XServerPixelBuffer::IsWindowValid() const {
     213             :   XWindowAttributes attributes;
     214             :   {
     215           0 :     XErrorTrap error_trap(display_);
     216           0 :     if (!XGetWindowAttributes(display_, window_, &attributes) ||
     217           0 :         error_trap.GetLastErrorAndDisable() != 0) {
     218           0 :       return false;
     219             :     }
     220             :   }
     221           0 :   return true;
     222             : }
     223             : 
     224           0 : void XServerPixelBuffer::Synchronize() {
     225           0 :   if (shm_segment_info_ && !shm_pixmap_) {
     226             :     // XShmGetImage can fail if the display is being reconfigured.
     227           0 :     XErrorTrap error_trap(display_);
     228             :     // XShmGetImage fails if the window is partially out of screen.
     229           0 :     xshm_get_image_succeeded_ =
     230           0 :         XShmGetImage(display_, window_, x_image_, 0, 0, AllPlanes);
     231             :   }
     232           0 : }
     233             : 
     234           0 : bool XServerPixelBuffer::CaptureRect(const DesktopRect& rect,
     235             :                                      DesktopFrame* frame) {
     236           0 :   assert(rect.right() <= window_size_.width());
     237           0 :   assert(rect.bottom() <= window_size_.height());
     238             : 
     239             :   uint8_t* data;
     240             : 
     241           0 :   if (shm_segment_info_ && (shm_pixmap_ || xshm_get_image_succeeded_)) {
     242           0 :     if (shm_pixmap_) {
     243           0 :       XCopyArea(display_, window_, shm_pixmap_, shm_gc_,
     244           0 :                 rect.left(), rect.top(), rect.width(), rect.height(),
     245           0 :                 rect.left(), rect.top());
     246           0 :       XSync(display_, False);
     247             :     }
     248           0 :     data = reinterpret_cast<uint8_t*>(x_image_->data) +
     249           0 :         rect.top() * x_image_->bytes_per_line +
     250           0 :         rect.left() * x_image_->bits_per_pixel / 8;
     251             :   } else {
     252           0 :     if (x_image_)
     253           0 :       XDestroyImage(x_image_);
     254           0 :     x_image_ = XGetImage(display_, window_, rect.left(), rect.top(),
     255           0 :                          rect.width(), rect.height(), AllPlanes, ZPixmap);
     256           0 :     if (!x_image_)
     257           0 :       return false;
     258             : 
     259           0 :     data = reinterpret_cast<uint8_t*>(x_image_->data);
     260             :   }
     261             : 
     262           0 :   if (IsXImageRGBFormat(x_image_)) {
     263           0 :     FastBlit(data, rect, frame);
     264             :   } else {
     265           0 :     SlowBlit(data, rect, frame);
     266             :   }
     267             : 
     268           0 :   return true;
     269             : }
     270             : 
     271           0 : void XServerPixelBuffer::FastBlit(uint8_t* image,
     272             :                                   const DesktopRect& rect,
     273             :                                   DesktopFrame* frame) {
     274           0 :   uint8_t* src_pos = image;
     275           0 :   int src_stride = x_image_->bytes_per_line;
     276           0 :   int dst_x = rect.left(), dst_y = rect.top();
     277             : 
     278           0 :   uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
     279           0 :   dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
     280             : 
     281           0 :   int height = rect.height();
     282           0 :   int row_bytes = rect.width() * DesktopFrame::kBytesPerPixel;
     283           0 :   for (int y = 0; y < height; ++y) {
     284           0 :     memcpy(dst_pos, src_pos, row_bytes);
     285           0 :     src_pos += src_stride;
     286           0 :     dst_pos += frame->stride();
     287             :   }
     288           0 : }
     289             : 
     290           0 : void XServerPixelBuffer::SlowBlit(uint8_t* image,
     291             :                                   const DesktopRect& rect,
     292             :                                   DesktopFrame* frame) {
     293           0 :   int src_stride = x_image_->bytes_per_line;
     294           0 :   int dst_x = rect.left(), dst_y = rect.top();
     295           0 :   int width = rect.width(), height = rect.height();
     296             : 
     297           0 :   uint32_t red_mask = x_image_->red_mask;
     298           0 :   uint32_t green_mask = x_image_->red_mask;
     299           0 :   uint32_t blue_mask = x_image_->blue_mask;
     300             : 
     301           0 :   uint32_t red_shift = MaskToShift(red_mask);
     302           0 :   uint32_t green_shift = MaskToShift(green_mask);
     303           0 :   uint32_t blue_shift = MaskToShift(blue_mask);
     304             : 
     305           0 :   int bits_per_pixel = x_image_->bits_per_pixel;
     306             : 
     307           0 :   uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
     308           0 :   uint8_t* src_pos = image;
     309           0 :   dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
     310             :   // TODO(hclam): Optimize, perhaps using MMX code or by converting to
     311             :   // YUV directly.
     312             :   // TODO(sergeyu): This code doesn't handle XImage byte order properly and
     313             :   // won't work with 24bpp images. Fix it.
     314           0 :   for (int y = 0; y < height; y++) {
     315           0 :     uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos);
     316           0 :     uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos);
     317           0 :     uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos);
     318           0 :     for (int x = 0; x < width; x++) {
     319             :       // Dereference through an appropriately-aligned pointer.
     320             :       uint32_t pixel;
     321           0 :       if (bits_per_pixel == 32) {
     322           0 :         pixel = src_pos_32[x];
     323           0 :       } else if (bits_per_pixel == 16) {
     324           0 :         pixel = src_pos_16[x];
     325             :       } else {
     326           0 :         pixel = src_pos[x];
     327             :       }
     328           0 :       uint32_t r = (pixel & red_mask) << red_shift;
     329           0 :       uint32_t g = (pixel & green_mask) << green_shift;
     330           0 :       uint32_t b = (pixel & blue_mask) << blue_shift;
     331             :       // Write as 32-bit RGB.
     332           0 :       dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
     333           0 :           ((b >> 24) & 0xff);
     334             :     }
     335           0 :     dst_pos += frame->stride();
     336           0 :     src_pos += src_stride;
     337             :   }
     338           0 : }
     339             : 
     340             : }  // namespace webrtc

Generated by: LCOV version 1.13