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.
5 #include "media/tools/player_x11/x11_video_renderer.h"
9 #include <X11/extensions/Xrender.h>
10 #include <X11/extensions/Xcomposite.h>
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"
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
)),
25 static_cast<char*>(malloc(width
* height
* 4)),
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
;
39 // First look for a 32-bit format which ignores the alpha value.
40 XRenderPictFormat templ
;
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;
51 static const unsigned long kMask
=
52 PictFormatType
| PictFormatDepth
|
53 PictFormatRed
| PictFormatRedMask
|
54 PictFormatGreen
| PictFormatGreenMask
|
55 PictFormatBlue
| PictFormatBlueMask
|
58 pictformat
= XRenderFindFormat(dpy
, kMask
, &templ
, 0 /* first result */);
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
64 pictformat
= XRenderFindStandardFormat(dpy
, PictStandardARGB32
);
65 CHECK(pictformat
) << "XRender ARGB32 not supported.";
71 X11VideoRenderer::X11VideoRenderer(Display
* display
, Window window
)
79 X11VideoRenderer::~X11VideoRenderer() {
81 XDestroyImage(image_
);
83 XRenderFreePicture(display_
, picture_
);
86 void X11VideoRenderer::Paint(media::VideoFrame
* video_frame
) {
88 Initialize(video_frame
->coded_size(), video_frame
->visible_rect());
90 const int coded_width
= video_frame
->coded_size().width();
91 const int coded_height
= video_frame
->coded_size().height();
92 const int visible_width
= video_frame
->visible_rect().width();
93 const int visible_height
= video_frame
->visible_rect().height();
95 // Check if we need to reallocate our XImage.
96 if (image_
->width
!= coded_width
|| image_
->height
!= coded_height
) {
97 XDestroyImage(image_
);
98 image_
= CreateImage(display_
, coded_width
, coded_height
);
101 // Convert YUV frame to RGB.
102 DCHECK(video_frame
->format() == media::VideoFrame::YV12
||
103 video_frame
->format() == media::VideoFrame::YV16
);
104 DCHECK(video_frame
->stride(media::VideoFrame::kUPlane
) ==
105 video_frame
->stride(media::VideoFrame::kVPlane
));
107 DCHECK(image_
->data
);
108 media::YUVType yuv_type
=
109 (video_frame
->format() == media::VideoFrame::YV12
) ?
110 media::YV12
: media::YV16
;
111 media::ConvertYUVToRGB32(video_frame
->data(media::VideoFrame::kYPlane
),
112 video_frame
->data(media::VideoFrame::kUPlane
),
113 video_frame
->data(media::VideoFrame::kVPlane
),
114 (uint8
*)image_
->data
, coded_width
, coded_height
,
115 video_frame
->stride(media::VideoFrame::kYPlane
),
116 video_frame
->stride(media::VideoFrame::kUPlane
),
117 image_
->bytes_per_line
,
121 // If XRender is used, we'll upload the image to a pixmap. And then
122 // creats a picture from the pixmap and composite the picture over
123 // the picture represending the window.
127 memset(&image
, 0, sizeof(image
));
128 image
.width
= coded_width
;
129 image
.height
= coded_height
;
131 image
.bits_per_pixel
= 32;
132 image
.format
= ZPixmap
;
133 image
.byte_order
= LSBFirst
;
134 image
.bitmap_unit
= 8;
135 image
.bitmap_bit_order
= LSBFirst
;
136 image
.bytes_per_line
= image_
->bytes_per_line
;
137 image
.red_mask
= 0xff;
138 image
.green_mask
= 0xff00;
139 image
.blue_mask
= 0xff0000;
140 image
.data
= image_
->data
;
142 // Creates a pixmap and uploads from the XImage.
143 unsigned long pixmap
= XCreatePixmap(display_
, window_
,
144 visible_width
, visible_height
,
146 GC gc
= XCreateGC(display_
, pixmap
, 0, NULL
);
147 XPutImage(display_
, pixmap
, gc
, &image
,
148 video_frame
->visible_rect().x(),
149 video_frame
->visible_rect().y(),
151 visible_width
, visible_height
);
152 XFreeGC(display_
, gc
);
154 // Creates the picture representing the pixmap.
155 unsigned long picture
= XRenderCreatePicture(
156 display_
, pixmap
, GetRenderARGB32Format(display_
), 0, NULL
);
158 // Composite the picture over the picture representing the window.
159 XRenderComposite(display_
, PictOpSrc
, picture
, 0,
160 picture_
, 0, 0, 0, 0, 0, 0,
161 visible_width
, visible_height
);
163 XRenderFreePicture(display_
, picture
);
164 XFreePixmap(display_
, pixmap
);
168 // If XRender is not used, simply put the image to the server.
169 // This will have a tearing effect but this is OK.
170 // TODO(hclam): Upload the image to a pixmap and do XCopyArea()
172 GC gc
= XCreateGC(display_
, window_
, 0, NULL
);
173 XPutImage(display_
, window_
, gc
, image_
,
174 video_frame
->visible_rect().x(),
175 video_frame
->visible_rect().y(),
176 0, 0, visible_width
, visible_height
);
178 XFreeGC(display_
, gc
);
181 void X11VideoRenderer::Initialize(gfx::Size coded_size
,
182 gfx::Rect visible_rect
) {
184 VLOG(0) << "Initializing X11 Renderer...";
186 // Resize the window to fit that of the video.
187 XResizeWindow(display_
, window_
, visible_rect
.width(), visible_rect
.height());
188 image_
= CreateImage(display_
, coded_size
.width(), coded_size
.height());
190 // Testing XRender support. We'll use the very basic of XRender
191 // so if it presents it is already good enough. We don't need
192 // to check its version.
194 use_render_
= XRenderQueryExtension(display_
, &dummy
, &dummy
);
197 VLOG(0) << "Using XRender extension.";
199 // If we are using XRender, we'll create a picture representing the
201 XWindowAttributes attr
;
202 XGetWindowAttributes(display_
, window_
, &attr
);
204 XRenderPictFormat
* pictformat
= XRenderFindVisualFormat(
207 CHECK(pictformat
) << "XRender does not support default visual";
209 picture_
= XRenderCreatePicture(display_
, window_
, pictformat
, 0, NULL
);
210 CHECK(picture_
) << "Backing picture not created";