OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/tools/player_x11/x11_video_renderer.h" |
| 6 |
| 7 #include <dlfcn.h> |
| 8 #include <X11/Xutil.h> |
| 9 #include <X11/extensions/Xrender.h> |
| 10 #include <X11/extensions/Xcomposite.h> |
| 11 |
| 12 #include "base/bind.h" |
| 13 #include "base/message_loop/message_loop.h" |
| 14 #include "media/base/video_frame.h" |
| 15 #include "media/base/yuv_convert.h" |
| 16 |
| 17 // Creates a 32-bit XImage. |
| 18 static XImage* CreateImage(Display* display, int width, int height) { |
| 19 VLOG(0) << "Allocating XImage " << width << "x" << height; |
| 20 return XCreateImage(display, |
| 21 DefaultVisual(display, DefaultScreen(display)), |
| 22 DefaultDepth(display, DefaultScreen(display)), |
| 23 ZPixmap, |
| 24 0, |
| 25 static_cast<char*>(malloc(width * height * 4)), |
| 26 width, |
| 27 height, |
| 28 32, |
| 29 width * 4); |
| 30 } |
| 31 |
| 32 // Returns the picture format for ARGB. |
| 33 // This method is originally from chrome/common/x11_util.cc. |
| 34 static XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { |
| 35 static XRenderPictFormat* pictformat = NULL; |
| 36 if (pictformat) |
| 37 return pictformat; |
| 38 |
| 39 // First look for a 32-bit format which ignores the alpha value. |
| 40 XRenderPictFormat templ; |
| 41 templ.depth = 32; |
| 42 templ.type = PictTypeDirect; |
| 43 templ.direct.red = 16; |
| 44 templ.direct.green = 8; |
| 45 templ.direct.blue = 0; |
| 46 templ.direct.redMask = 0xff; |
| 47 templ.direct.greenMask = 0xff; |
| 48 templ.direct.blueMask = 0xff; |
| 49 templ.direct.alphaMask = 0; |
| 50 |
| 51 static const unsigned long kMask = |
| 52 PictFormatType | PictFormatDepth | |
| 53 PictFormatRed | PictFormatRedMask | |
| 54 PictFormatGreen | PictFormatGreenMask | |
| 55 PictFormatBlue | PictFormatBlueMask | |
| 56 PictFormatAlphaMask; |
| 57 |
| 58 pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */); |
| 59 |
| 60 if (!pictformat) { |
| 61 // Not all X servers support xRGB32 formats. However, the XRender spec |
| 62 // says that they must support an ARGB32 format, so we can always return |
| 63 // that. |
| 64 pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32); |
| 65 CHECK(pictformat) << "XRender ARGB32 not supported."; |
| 66 } |
| 67 |
| 68 return pictformat; |
| 69 } |
| 70 |
| 71 X11VideoRenderer::X11VideoRenderer(Display* display, Window window) |
| 72 : display_(display), |
| 73 window_(window), |
| 74 image_(NULL), |
| 75 picture_(0), |
| 76 use_render_(false) { |
| 77 } |
| 78 |
| 79 X11VideoRenderer::~X11VideoRenderer() { |
| 80 if (image_) |
| 81 XDestroyImage(image_); |
| 82 if (use_render_) |
| 83 XRenderFreePicture(display_, picture_); |
| 84 } |
| 85 |
| 86 void X11VideoRenderer::Paint( |
| 87 const scoped_refptr<media::VideoFrame>& video_frame) { |
| 88 if (!image_) |
| 89 Initialize(video_frame->coded_size(), video_frame->visible_rect()); |
| 90 |
| 91 const int coded_width = video_frame->coded_size().width(); |
| 92 const int coded_height = video_frame->coded_size().height(); |
| 93 const int visible_width = video_frame->visible_rect().width(); |
| 94 const int visible_height = video_frame->visible_rect().height(); |
| 95 |
| 96 // Check if we need to reallocate our XImage. |
| 97 if (image_->width != coded_width || image_->height != coded_height) { |
| 98 XDestroyImage(image_); |
| 99 image_ = CreateImage(display_, coded_width, coded_height); |
| 100 } |
| 101 |
| 102 // Convert YUV frame to RGB. |
| 103 DCHECK(video_frame->format() == media::VideoFrame::YV12 || |
| 104 video_frame->format() == media::VideoFrame::I420 || |
| 105 video_frame->format() == media::VideoFrame::YV16); |
| 106 DCHECK(video_frame->stride(media::VideoFrame::kUPlane) == |
| 107 video_frame->stride(media::VideoFrame::kVPlane)); |
| 108 |
| 109 DCHECK(image_->data); |
| 110 media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12 || |
| 111 video_frame->format() == media::VideoFrame::I420) |
| 112 ? media::YV12 |
| 113 : media::YV16; |
| 114 media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), |
| 115 video_frame->data(media::VideoFrame::kUPlane), |
| 116 video_frame->data(media::VideoFrame::kVPlane), |
| 117 (uint8*)image_->data, coded_width, coded_height, |
| 118 video_frame->stride(media::VideoFrame::kYPlane), |
| 119 video_frame->stride(media::VideoFrame::kUPlane), |
| 120 image_->bytes_per_line, |
| 121 yuv_type); |
| 122 |
| 123 if (use_render_) { |
| 124 // If XRender is used, we'll upload the image to a pixmap. And then |
| 125 // creats a picture from the pixmap and composite the picture over |
| 126 // the picture represending the window. |
| 127 |
| 128 // Creates a XImage. |
| 129 XImage image; |
| 130 memset(&image, 0, sizeof(image)); |
| 131 image.width = coded_width; |
| 132 image.height = coded_height; |
| 133 image.depth = 32; |
| 134 image.bits_per_pixel = 32; |
| 135 image.format = ZPixmap; |
| 136 image.byte_order = LSBFirst; |
| 137 image.bitmap_unit = 8; |
| 138 image.bitmap_bit_order = LSBFirst; |
| 139 image.bytes_per_line = image_->bytes_per_line; |
| 140 image.red_mask = 0xff; |
| 141 image.green_mask = 0xff00; |
| 142 image.blue_mask = 0xff0000; |
| 143 image.data = image_->data; |
| 144 |
| 145 // Creates a pixmap and uploads from the XImage. |
| 146 unsigned long pixmap = XCreatePixmap(display_, window_, |
| 147 visible_width, visible_height, |
| 148 32); |
| 149 GC gc = XCreateGC(display_, pixmap, 0, NULL); |
| 150 XPutImage(display_, pixmap, gc, &image, |
| 151 video_frame->visible_rect().x(), |
| 152 video_frame->visible_rect().y(), |
| 153 0, 0, |
| 154 visible_width, visible_height); |
| 155 XFreeGC(display_, gc); |
| 156 |
| 157 // Creates the picture representing the pixmap. |
| 158 unsigned long picture = XRenderCreatePicture( |
| 159 display_, pixmap, GetRenderARGB32Format(display_), 0, NULL); |
| 160 |
| 161 // Composite the picture over the picture representing the window. |
| 162 XRenderComposite(display_, PictOpSrc, picture, 0, |
| 163 picture_, 0, 0, 0, 0, 0, 0, |
| 164 visible_width, visible_height); |
| 165 |
| 166 XRenderFreePicture(display_, picture); |
| 167 XFreePixmap(display_, pixmap); |
| 168 return; |
| 169 } |
| 170 |
| 171 // If XRender is not used, simply put the image to the server. |
| 172 // This will have a tearing effect but this is OK. |
| 173 // TODO(hclam): Upload the image to a pixmap and do XCopyArea() |
| 174 // to the window. |
| 175 GC gc = XCreateGC(display_, window_, 0, NULL); |
| 176 XPutImage(display_, window_, gc, image_, |
| 177 video_frame->visible_rect().x(), |
| 178 video_frame->visible_rect().y(), |
| 179 0, 0, visible_width, visible_height); |
| 180 XFlush(display_); |
| 181 XFreeGC(display_, gc); |
| 182 } |
| 183 |
| 184 void X11VideoRenderer::Initialize(gfx::Size coded_size, |
| 185 gfx::Rect visible_rect) { |
| 186 CHECK(!image_); |
| 187 VLOG(0) << "Initializing X11 Renderer..."; |
| 188 |
| 189 // Resize the window to fit that of the video. |
| 190 XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); |
| 191 image_ = CreateImage(display_, coded_size.width(), coded_size.height()); |
| 192 |
| 193 // Testing XRender support. We'll use the very basic of XRender |
| 194 // so if it presents it is already good enough. We don't need |
| 195 // to check its version. |
| 196 int dummy; |
| 197 use_render_ = XRenderQueryExtension(display_, &dummy, &dummy); |
| 198 |
| 199 if (use_render_) { |
| 200 VLOG(0) << "Using XRender extension."; |
| 201 |
| 202 // If we are using XRender, we'll create a picture representing the |
| 203 // window. |
| 204 XWindowAttributes attr; |
| 205 XGetWindowAttributes(display_, window_, &attr); |
| 206 |
| 207 XRenderPictFormat* pictformat = XRenderFindVisualFormat( |
| 208 display_, |
| 209 attr.visual); |
| 210 CHECK(pictformat) << "XRender does not support default visual"; |
| 211 |
| 212 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); |
| 213 CHECK(picture_) << "Backing picture not created"; |
| 214 } |
| 215 } |
OLD | NEW |