OLD | NEW |
(Empty) | |
| 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/include/critical_section_wrapper.h" |
| 14 #include "webrtc/system_wrappers/include/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 const VideoFrame& 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 VideoFrame& 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 need
s 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 |
OLD | NEW |