1 /* 2 * Copyright (c) 2012 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/video_render/linux/video_x11_channel.h" 12 13 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 14 #include "webrtc/system_wrappers/interface/trace.h" 15 16 namespace webrtc { 17 18 #define DISP_MAX 128 19 20 static Display *dispArray[DISP_MAX]; 21 static int dispCount = 0; 22 23 24 VideoX11Channel::VideoX11Channel(int32_t id) : 25 _crit(*CriticalSectionWrapper::CreateCriticalSection()), _display(NULL), 26 _shminfo(), _image(NULL), _window(0L), _gc(NULL), 27 _width(DEFAULT_RENDER_FRAME_WIDTH), 28 _height(DEFAULT_RENDER_FRAME_HEIGHT), _outWidth(0), _outHeight(0), 29 _xPos(0), _yPos(0), _prepared(false), _dispCount(0), _buffer(NULL), 30 _top(0.0), _left(0.0), _right(0.0), _bottom(0.0), 31 _Id(id) 32 { 33 } 34 35 VideoX11Channel::~VideoX11Channel() 36 { 37 if (_prepared) 38 { 39 _crit.Enter(); 40 ReleaseWindow(); 41 _crit.Leave(); 42 } 43 delete &_crit; 44 } 45 46 int32_t VideoX11Channel::RenderFrame(const uint32_t streamId, 47 I420VideoFrame& videoFrame) { 48 CriticalSectionScoped cs(&_crit); 49 if (_width != videoFrame.width() || _height 50 != videoFrame.height()) { 51 if (FrameSizeChange(videoFrame.width(), videoFrame.height(), 1) == -1) { 52 return -1; 53 } 54 } 55 return DeliverFrame(videoFrame); 56 } 57 58 int32_t VideoX11Channel::FrameSizeChange(int32_t width, 59 int32_t height, 60 int32_t /*numberOfStreams */) 61 { 62 CriticalSectionScoped cs(&_crit); 63 if (_prepared) 64 { 65 RemoveRenderer(); 66 } 67 if (CreateLocalRenderer(width, height) == -1) 68 { 69 return -1; 70 } 71 72 return 0; 73 } 74 75 int32_t VideoX11Channel::DeliverFrame(const I420VideoFrame& videoFrame) { 76 CriticalSectionScoped cs(&_crit); 77 if (!_prepared) { 78 return 0; 79 } 80 81 if (!dispArray[_dispCount]) { 82 return -1; 83 } 84 85 ConvertFromI420(videoFrame, kARGB, 0, _buffer); 86 87 // Put image in window. 88 XShmPutImage(_display, _window, _gc, _image, 0, 0, _xPos, _yPos, _width, 89 _height, True); 90 91 // Very important for the image to update properly! 92 XSync(_display, False); 93 return 0; 94 } 95 96 int32_t VideoX11Channel::GetFrameSize(int32_t& width, int32_t& height) 97 { 98 width = _width; 99 height = _height; 100 101 return 0; 102 } 103 104 int32_t VideoX11Channel::Init(Window window, float left, float top, 105 float right, float bottom) 106 { 107 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 108 __FUNCTION__); 109 CriticalSectionScoped cs(&_crit); 110 111 _window = window; 112 _left = left; 113 _right = right; 114 _top = top; 115 _bottom = bottom; 116 117 _display = XOpenDisplay(NULL); // Use default display 118 if (!_window || !_display) 119 { 120 return -1; 121 } 122 123 if (dispCount < DISP_MAX) 124 { 125 dispArray[dispCount] = _display; 126 _dispCount = dispCount; 127 dispCount++; 128 } 129 else 130 { 131 return -1; 132 } 133 134 if ((1 < left || left < 0) || (1 < top || top < 0) || (1 < right || right 135 < 0) || (1 < bottom || bottom < 0)) 136 { 137 return -1; 138 } 139 140 // calculate position and size of rendered video 141 int x, y; 142 unsigned int winWidth, winHeight, borderwidth, depth; 143 Window rootret; 144 if (XGetGeometry(_display, _window, &rootret, &x, &y, &winWidth, 145 &winHeight, &borderwidth, &depth) == 0) 146 { 147 return -1; 148 } 149 150 _xPos = (int32_t) (winWidth * left); 151 _yPos = (int32_t) (winHeight * top); 152 _outWidth = (int32_t) (winWidth * (right - left)); 153 _outHeight = (int32_t) (winHeight * (bottom - top)); 154 if (_outWidth % 2) 155 _outWidth++; // the renderer want's sizes that are multiples of two 156 if (_outHeight % 2) 157 _outHeight++; 158 159 _gc = XCreateGC(_display, _window, 0, 0); 160 if (!_gc) { 161 // Failed to create the graphics context. 162 assert(false); 163 return -1; 164 } 165 166 if (CreateLocalRenderer(winWidth, winHeight) == -1) 167 { 168 return -1; 169 } 170 return 0; 171 172 } 173 174 int32_t VideoX11Channel::ChangeWindow(Window window) 175 { 176 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 177 __FUNCTION__); 178 CriticalSectionScoped cs(&_crit); 179 180 // Stop the rendering, if we are rendering... 181 RemoveRenderer(); 182 _window = window; 183 184 // calculate position and size of rendered video 185 int x, y; 186 unsigned int winWidth, winHeight, borderwidth, depth; 187 Window rootret; 188 if (XGetGeometry(_display, _window, &rootret, &x, &y, &winWidth, 189 &winHeight, &borderwidth, &depth) == -1) 190 { 191 return -1; 192 } 193 _xPos = (int) (winWidth * _left); 194 _yPos = (int) (winHeight * _top); 195 _outWidth = (int) (winWidth * (_right - _left)); 196 _outHeight = (int) (winHeight * (_bottom - _top)); 197 if (_outWidth % 2) 198 _outWidth++; // the renderer want's sizes that are multiples of two 199 if (_outHeight % 2) 200 _outHeight++; 201 202 // Prepare rendering using the 203 if (CreateLocalRenderer(_width, _height) == -1) 204 { 205 return -1; 206 } 207 return 0; 208 } 209 210 int32_t VideoX11Channel::ReleaseWindow() 211 { 212 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 213 __FUNCTION__); 214 CriticalSectionScoped cs(&_crit); 215 216 RemoveRenderer(); 217 if (_gc) { 218 XFreeGC(_display, _gc); 219 _gc = NULL; 220 } 221 if (_display) 222 { 223 XCloseDisplay(_display); 224 _display = NULL; 225 } 226 return 0; 227 } 228 229 int32_t VideoX11Channel::CreateLocalRenderer(int32_t width, int32_t height) 230 { 231 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 232 __FUNCTION__); 233 CriticalSectionScoped cs(&_crit); 234 235 if (!_window || !_display) 236 { 237 return -1; 238 } 239 240 if (_prepared) 241 { 242 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _Id, 243 "Renderer already prepared, exits."); 244 return -1; 245 } 246 247 _width = width; 248 _height = height; 249 250 // create shared memory image 251 _image = XShmCreateImage(_display, CopyFromParent, 24, ZPixmap, NULL, 252 &_shminfo, _width, _height); // this parameter needs to be the same for some reason. 253 _shminfo.shmid = shmget(IPC_PRIVATE, (_image->bytes_per_line 254 * _image->height), IPC_CREAT | 0777); 255 _shminfo.shmaddr = _image->data = (char*) shmat(_shminfo.shmid, 0, 0); 256 if (_image->data == reinterpret_cast<char*>(-1)) 257 { 258 return -1; 259 } 260 _buffer = (unsigned char*) _image->data; 261 _shminfo.readOnly = False; 262 263 // attach image to display 264 if (!XShmAttach(_display, &_shminfo)) 265 { 266 //printf("XShmAttach failed !\n"); 267 return -1; 268 } 269 XSync(_display, False); 270 271 _prepared = true; 272 return 0; 273 } 274 275 int32_t VideoX11Channel::RemoveRenderer() 276 { 277 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 278 __FUNCTION__); 279 280 if (!_prepared) 281 { 282 return 0; 283 } 284 _prepared = false; 285 286 // Free the memory. 287 XShmDetach(_display, &_shminfo); 288 XDestroyImage( _image ); 289 _image = NULL; 290 shmdt(_shminfo.shmaddr); 291 _shminfo.shmaddr = NULL; 292 _buffer = NULL; 293 shmctl(_shminfo.shmid, IPC_RMID, 0); 294 _shminfo.shmid = 0; 295 return 0; 296 } 297 298 int32_t VideoX11Channel::GetStreamProperties(uint32_t& zOrder, 299 float& left, float& top, 300 float& right, float& bottom) const 301 { 302 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _Id, "%s", 303 __FUNCTION__); 304 305 zOrder = 0; // no z-order support yet 306 left = _left; 307 top = _top; 308 right = _right; 309 bottom = _bottom; 310 311 return 0; 312 } 313 314 315 } // namespace webrtc 316