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 |